day09

本文介绍了Java中的抽象类、接口及其多态特性,包括抽象方法的使用、final关键字的作用、接口的定义与实现,以及多态的概念、应用和优缺点。通过实例展示了如何在实际项目中运用这些概念来组织代码和实现类间的关系。
摘要由CSDN通过智能技术生成

day09

一、抽象类

1.1 格式
关键字 abstract

权限修饰符 abstract class 类名 {

}
public abstract class Person {

}
1.2 作用
1. 提取一些类共有的内容到抽象类中
2. 主要用来当父类
1.3 特点
1. 抽象类中可以放抽象方法的。
2. 抽象方法一定要放在抽象类中。
3. 抽象类不能实例化(也就是不能创建对象)
		抽象类虽然不能创建对象,但是它的子类可以创建对象

抽象方法的格式:
权限修饰符 abstract 返回值类型 方法名(参数列表);
1.4 抽象类中的成员
成员变量:
	普通的成员变量、静态的变量、常量
成员方法:
	普通的成员方法、抽象方法
构造方法:
	有构造方法(但是不能用来创建对象,主要是用来对抽象类中的成员进行初始化,方便子类使用)
package com.ujiuye.demo01_抽象类;

/*
       抽象的人类
 */
public abstract class Person {

    String name;
    int age;
    static String sex;
    final String country = "中国";

    //抽象方法
    public abstract void eat();
    public abstract void sleep();

    //普通的成员方法
    public void playGame(){

    }
}

1.5 如何处理抽象类中的抽象方法
1. 将类声明为抽象类    【没有意义,所以不建议】
2. 将父类中的抽象方法全部重写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUxwRZAs-1620291107393)(img/image-20210416113957371.png)]

/*
	方式一:声明为抽象
 */
public abstract class Nurse extends Person {
    
} 
 
/*
 	方式二:全部重写
*/
public class Nurse extends Person {
    @Override
    public void eat() {
        System.out.println("一个小护士喜欢吃饭...");
    }

    @Override
    public void sleep() {
        System.out.println("躺着睡觉");
    }
}
员工类练习:用继承、抽象类、抽象方法进行改进。

程序员类:		 属性(姓名、工号、工资、奖金)    行为(工作:软件开发)
测试工程师类:	    属性(姓名、工号、工资)   		 行为(工作:软件测试)
项目经理类:		 属性(姓名、工号、工资、奖金)    行为(工作:控制进度)
package com.ujiuye.demo01_抽象类;

/*
    抽象员工类
 */
public abstract class Worker {

    String name;
    int id;
    int salary;

    public abstract void work();

    public void show(){
        System.out.println(name + ", " + id + ", " + salary);
    }
}

/*
	Java开发工程师
 */
public class JavaWorker extends Worker {

    int bonus;

    /*
        生成构造方法的快捷键: alt + insert
     */

    public JavaWorker() {
    }
    public JavaWorker(String name, int id, int salary, int bonus) {
        this.name = name;
        this.id = id;
        this.salary = salary;
        this.bonus = bonus;
    }

    @Override
    public void work() {
        System.out.println("软件开发");
    }

    @Override
    public void show() {
        super.show();
        System.out.println(bonus);
    }
}

/*
	测试工程师类
 */
public class TestWorker extends Worker {

    public TestWorker() {
    }
    public TestWorker(String name, int id, int salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    @Override
    public void work() {
        System.out.println("软件测试");
    }

    @Override
    public void show() {
        super.show();
    }
}

/* 
	项目经理类
 */
public class PMWorker extends Worker {

    int bonus;

    public PMWorker() {
    }
    public PMWorker(String name, int id, int salary, int bonus) {
        this.name = name;
        this.id = id;
        this.salary = salary;
        this.bonus = bonus;
    }

    @Override
    public void work() {
        System.out.println("控制进度");
    }

    @Override
    public void show() {
        super.show();
        System.out.println(bonus);
    }
}

/*
	测试类
 */
public class Demo2 {

    public static void main(String[] args) {

        JavaWorker jw = new JavaWorker();
        JavaWorker jw2 = new JavaWorker("雷军", 1, 1, 10000000);
        jw.work();
        jw2.show();

        PMWorker pw = new PMWorker();
        pw.work();

    }
}

二、final关键字

final可以修饰类、方法、变量

修饰类:
	类不能被继承
修饰方法:
	方法不能被重写
修饰变量:
	变量变为了常量(常量就是在程序运行过程中不会发生改变的量)

注意:
	1. 常量在创建对象之前必须要完成初始化,否则报错
		1. 直接显示初始化
		2. 在构造方法中初始化
		3. 在构造代码块中初始化
	2. 一般我们声明常量的格式为:public static final 
public class Person {

    /*
        因为常量不能在程序运行过程中发生改变,所以常量一般都是记录一些固定的值,比如:圆周率PI,int类型的最大值MAX_VALUE

        一般我们定义常量的时候为了方便访问:都会默认写为 public static final 数据类型 变量名 = 常量值;

     */
    public static final int I = 10;

}

三、接口

接口也是Java中的一种引用数据类型。Java接口是一个能装方法的容器(并且这些方法一般都是抽象方法)。

接口相当于定义了一组规范。实现这个接口的类都要实现接口中的方法。

3.1 格式
关键字 interface

权限修饰符 interface 接口名 {

}

注意:接口也和类一样,可以编译生成一个class文件
3.2 特点
1. 接口不能实例化
2. 接口中没有构造方法(所以接口不能创建对象)
		那么接口如何创建对象?
		可以通过接口的实现类(也可以叫做接口的子类)创建对象
		
		关键字 implements
		interface 接口名 {
		
		}
		class 实现类 implements 接口名 {
		
		}
/*
	接口
 */
public interface A {

    public abstract void test();
}
/*
	实现类
 */
public class AImpl implements A {

    @Override
    public void test() {

        System.out.println("重写后的内容...");
    }
}

/*
	测试类
 */
public class Demo {

    public static void main(String[] args) {

//        A a = new A();
        AImpl a = new AImpl();
        a.test();
    }
}
3.3 接口中的成员
成员变量:
	接口中的只有常量,默认被public static final修饰
成员方法:
	1. 接口中的方法默认是抽象方法。默认被public abstract修饰
	2. 被default修饰的方法  【jdk8新增】
	3. 被static修饰的方法   【jdk8新增】
			只能通过 接口名.静态方法名 调用
	4. 被private修饰的方法  【jdk9新增】
构造方法:
	接口中没有构造方法
	为什么接口中不需要构造方法?
		因为接口中方法默认都是抽象的,接口中只有常量,这些都不需要进行初始化就可以使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T05sNhK2-1620291107397)(img/image-20210416140447770.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q1nAQjR1-1620291107398)(img/image-20210416140648330.png)]

3.4 类与类、类与接口、接口与接口之间的关系
类与类
1. 可以单继承
		class Fu {}
		class Zi extends Fu {}
2. 不可以多继承
		class Fu {}
		class Mu {}
		class Zi extends Fu, Mu {}     //错误
3. 可以多层继承(继承体系)
		class Ye {}
		class Fu extends Ye {}
		class Zi extends Fu {}
类与接口
1. 可以单实现
		interface A {}
		class AImpl implements A {}
2. 可以多实现
		interface A {}
		interface B {}
		class C implements A, B {}
注意:一个类可以先继承一个类,然后再多实现接口
如:
	class A {}
	interface B {}
	interface C {}
	
	class D extends A implements B, C {}
接口与接口
1. 可以单继承	
		interface A {}
		interface B extends A {}

2. 可以多继承
		interface A {}
		interface B {}
		interface C extends A, B {}
练习:
	1. 定义一个抽象动物类 Animal
			属性:姓名、年龄
			行为:吃饭、睡觉  (抽象方法)
	2. 定义一个AnimalTrain接口
			行为:开车
	3. 定义一个猫类继承Animal类
	4. 定义一个狗类继承Animal类
	5. 定义一个超狗类继承Animal,并且会开车(也就是实现接口)
	6. 在测试中创建猫类、狗类、超狗类并进行测试
package com.ujiuye.demo03_接口;

/*
    抽象动物类Animal
 */
abstract class Animal {

    String name;
    int age;

    public abstract void eat();
    public abstract void sleep();
}

/*
    AnimalTrain接口
 */
interface AnimalTrain {

    public abstract void driveCar();
}

/*
    猫类
 */
class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫趴着睡觉");
    }
}

/*
    狗类
 */
class Dog extends Animal {


    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    @Override
    public void sleep() {
        System.out.println("狗斜着身子睡觉");
    }
}

/*
    超狗
 */
class SuperDog extends Animal implements AnimalTrain {


    @Override
    public void eat() {
        System.out.println("超狗吃海鲜");
    }

    @Override
    public void sleep() {
        System.out.println("超狗睡在100平米的大床上");
    }

    @Override
    public void driveCar() {
        System.out.println("超狗会开车");
    }
}

public class Demo2 {

    public static void main(String[] args) {

        Cat c = new Cat();
        c.eat();
        c.sleep();
        System.out.println("---------");
        Dog d = new Dog();
        d.eat();
        d.sleep();
        System.out.println("---------");
        SuperDog sd = new SuperDog();
        sd.eat();
        sd.sleep();
        sd.driveCar();

    }
}

四、多态

面向对象三大特征:封装、继承、多态

生活中:比如跑,猫、狗、狮子,跑的形态是不一样的。比如飞:昆虫、鸟类、飞机,飞的形态是不一样的。以上这些,都是对于同一个行为,不同的事物有不同的表示形态。这些就是多态的体现。

4.1 概念
生活中多态: 	对于同一个行为,不同的事物有不同的表示形态
Java中的多态:对于同一个方法,不同的对象有不同的实现方式(实际上就是重写了)
4.2 前提
1. 有父类继承或者接口实现
2. 子类重写父类的方法  【如果方法不重写,那么就谈不上多态】
3. 父类引用指向子类对象 Fu f = new Zi();
package com.ujiuye.demo04_多态;

class Fu {

    public void play(){

    }
}

//1. 有父类继承或者接口实现
class Zi extends Fu {

    //2. 有方法的重写
    @Override
    public void play() {
        System.out.println("小男孩喜欢玩游戏");
    }
}


public class Demo {

    public static void main(String[] args) {

        //3. 父类引用指向子类对象
        Fu f = new Zi();

    }
}

4.3 多态中访问成员的特点

父类的类型 父类的引用 = new 子类的类型();

等号的左边:就是父类的引用

等号的右边:就是子类的类型

注意观察结果:1. 编译错不错 2. 结果是父类的还是子类的

访问成员变量的时候:
	编译的时候看的是左边(如果父类中有就不报错),运行的时候看的也是左边(结果也是父类中的内容)
	
访问成员方法的时候:
	编译的时候看的是左边(如果父类中有就不报错),运行的时候看的是右边(结果是子类中重写之后的内容)
package com.ujiuye.demo04_多态;

class A {

    int i = 10;
    int j = 30;

    public void test() {
        System.out.println("A...test");
    }

    public void aa(){
        System.out.println("A...aa");
    }
}

class B extends A {

    int i = 20;
    int k = 40;

    public void test() {
        System.out.println("B...test");
    }

    public void bb(){
        System.out.println("B...bb");
    }
}

public class Demo2 {

    public static void main(String[] args) {

        A a = new B();
//        System.out.println(a.i);    //10   //父类和子类都有,编译不报错,结果的是父类的
//        System.out.println(a.j);    //30   //父类中有,子类中没有,编译不报错,结果的是父类的
//        System.out.println(a.k);    //编译报错。父类中没有,子类中有

//        a.test();    //B...test   //父类和子类都有,编译不报错,结果是子类的
//        a.aa();      //A...aa     //父类中有,子类中没有,编译不报错,结果是父类的
//        a.bb();      //编译报错。 父类中没有,子类中有

    }
}
4.4 多态的好处
1. 提高了代码的可维护性  (由继承和实现保证)
2. 提高了代码的可扩展性  (由多态保证)
package com.ujiuye.demo04_多态;

abstract class Animal {
    String name;
    int age;

    public abstract void eat();
    public abstract void sleep();
}

class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鸡肉");
    }

    @Override
    public void sleep() {
        System.out.println("猫趴着睡觉");
    }
}

class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    @Override
    public void sleep() {
        System.out.println("狗趴着睡觉");
    }
}

class Snake extends Animal {

    @Override
    public void eat() {
        System.out.println("蛇吃老鼠");
    }

    @Override
    public void sleep() {
        System.out.println("蛇盘着睡觉");
    }
}

public class Demo3 {

    public static void main(String[] args) {

        Cat c = new Cat();
//        c.eat();
//        c.sleep();
//        feedCat(c);
        feed(c);
        System.out.println("----------");
        Cat c2 = new Cat();
//        c2.eat();
//        c2.sleep();
//        feedCat(c2);
        feed(c2);
        System.out.println("----------");
        Dog d = new Dog();
//        d.eat();
//        d.sleep();
//        feedDog(d);
        feed(d);
        System.out.println("----------");
        Dog d2 = new Dog();
//        d2.eat();
//        d2.sleep();
//        feedDog(d2);
        feed(d2);
        System.out.println("----------");
        Snake s = new Snake();
//        feedSnake(s);
        feed(s);
        System.out.println("----------");
        Snake s2 = new Snake();
//        feedSnake(s2);
        feed(s2);
    }

    /*
        养动物的方法
     */
    public static void feed(Animal a){  //Animal a = new Cat(); //Animal a = new Dog();
        a.eat();
        a.sleep();
    }

    /*
        养猫的方法
     */
//    public static void feedCat(Cat c){  //需要的是类这种类型,实际上需要的是该类的对象 Cat c = new Cat();
//        c.eat();
//        c.sleep();
//        //...7
//    }
    /*
        养狗的方法
     */
//    public static void feedDog(Dog d){
//        d.eat();
//        d.sleep();
//    }

    /*
        养蛇的方法
     */
//    public static void feedSnake(Snake s){
//        s.eat();
//        s.sleep();
//    }

}
4.5 多态的弊端
多态中,不能访问子类特有的功能?
	如何处理?
	1. 创建子类的对象,通过子类的对象访问
	2. 将父类的引用再转为子类的引用即可(因为父类的引用本来就是指向了子类的对象,所以可以转换) (向下转型)
4.6 向下转型及向上转型
向上转型
向上转型:由小的类型到大的类型
	Fu f = new Zi();   //从小的类型Zi到大的类型Fu
向下转型
向下转型:由大的类型到小的类型(这种转换是不安全,所以需要强制执行)

较小的数据类型 对象名 = (较小的数据类型)较大的数据类型; 

如何安全的转换呢?
	有一个关键字instanceof可以判断一个对象是否属于某一种类型
	格式:
		对象 instanceof 类型
		如果对象属于这种类型,那么返回true
		如果不属于那么返回false
	
package com.ujiuye.demo04_多态;

class Person {

    public void test(){
        System.out.println("Person...test");
    }
}

class Student extends Person {

    public void test(){
        System.out.println("Student...test");
    }
    public void show(){
        System.out.println("Student...show");
    }
}


public class Demo4 {

    public static void main(String[] args) {

        Person p = new Student();

//        p.test();
//        p.show();   //编译报错
        //方式一:创建子类的对象,通过子类的对象访问
//        Student s = new Student();
//        s.show();

        //方式二:向下转型   较小的数据类型 对象名 = (较小的数据类型)较大的数据类型;
        Student s = (Student)p;
        s.show();

//        Student s = new Student();
//        System.out.println(s instanceof Person);

    }
}
思考:
	1. 多态用在参数中	(参考上方的Animal类)
	2. 多态用在返回值中

ge com.ujiuye.demo04_多态;

class Person {

public void test(){
    System.out.println("Person...test");
}

}

class Student extends Person {

public void test(){
    System.out.println("Student...test");
}
public void show(){
    System.out.println("Student...show");
}

}

public class Demo4 {

public static void main(String[] args) {

    Person p = new Student();

// p.test();
// p.show(); //编译报错
//方式一:创建子类的对象,通过子类的对象访问
// Student s = new Student();
// s.show();

    //方式二:向下转型   较小的数据类型 对象名 = (较小的数据类型)较大的数据类型;
    Student s = (Student)p;
    s.show();

// Student s = new Student();
// System.out.println(s instanceof Person);

}

}


思考:
1. 多态用在参数中 (参考上方的Animal类)
2. 多态用在返回值中








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值