JavaSE学习笔记(八)—— 多态&抽象类&接口

一、多态

1.1 多态概述

  多态是指,同一个对象(事物),在不同时刻体现出来的不同状态。

  举例::

  猫可以是猫的类型。猫 m = new 猫();

  同时猫也是动物的一种,也可以把猫称为动物。动物 d = new 猫();

  再举一个例子:

  水在不同时刻的状态:液体,固体,气态

1.2 多态的前提

  1. 要有继承关系。
  2. 要有方法重写。
    其实没有也是可以的,但是如果没有这个就没有意义。
        动物 d = new 猫();
        d.show();
        动物 d = new 狗();
        d.show();
  3. 要有父类引用指向子类对象。
    父 f =  new 子();

1.3 多态中的成员访问特点

  • 成员变量
    编译看左边,运行看左边。
  • 构造方法

    创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
  • 成员方法

    编译看左边,运行看右边。
  • 静态方法

    编译看左边,运行看左边。
    (静态和类相关,算不上重写,所以,访问还是左边的)

  注:由于成员方法存在方法重写,所以它运行看右边。

class Fu {
    public int num = 100;

    public void show() {
        System.out.println("show Fu");
    }
    
    public static void function() {
        System.out.println("function Fu");
    }
}

class Zi extends Fu {
    public int num = 1000;
    public int num2 = 200;

    public void show() {
        System.out.println("show Zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }
    
    public static void function() {
        System.out.println("function Zi");
    }
}

class DuoTaiDemo {
    public static void main(String[] args) {
        //要有父类引用指向子类对象。
        //父 f =  new 子();
        Fu f = new Zi();
        System.out.println(f.num);//100
        //找不到符号
        //System.out.println(f.num2);
        
        f.show();//show Zi
        //找不到符号
        //f.method();
        f.function();//function Fu
    }
}

【内存图解】

1.4 多态的好处和弊端

【多态的好处】

  1. 提高了代码的维护性(继承保证)
  2. 提高了代码的扩展性(由多态保证)
class Animal {
    public void eat(){
        System.out.println("eat");
    }
    
    public void sleep(){
        System.out.println("sleep");
    }
}

class Dog extends Animal {
    public void eat(){
        System.out.println("狗吃肉");
    }
    
    public void sleep(){
        System.out.println("狗站着睡觉");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
    
    public void sleep() {
        System.out.println("猫趴着睡觉");
    }
}

class Pig extends Animal {
    public void eat() {
        System.out.println("猪吃白菜");
    }
    
    public void sleep() {
        System.out.println("猪侧着睡");
    }
}

//针对动物操作的工具类
class AnimalTool {
    private AnimalTool(){}

    /*
    //调用猫的功能
    public static void useCat(Cat c) {
        c.eat();
        c.sleep();
    }
    
    //调用狗的功能
    public static void useDog(Dog d) {
        d.eat();
        d.sleep();
    }
    
    //调用猪的功能
    public static void usePig(Pig p) {
        p.eat();
        p.sleep();
    }
    */
    public static void useAnimal(Animal a) {
        a.eat();
        a.sleep();
    }
    
}

class DuoTaiDemo2 {
    public static void main(String[] args) {
        //我喜欢猫,就养了一只
        Cat c = new Cat();
        c.eat();
        c.sleep();
        
        //我很喜欢猫,所以,又养了一只
        Cat c2 = new Cat();
        c2.eat();
        c2.sleep();
        
        //我特别喜欢猫,又养了一只
        Cat c3 = new Cat();
        c3.eat();
        c3.sleep();
        //...
        System.out.println("--------------");
        //问题来了,我养了很多只猫,每次创建对象是可以接受的
        //但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。
        //我们准备用方法改进
        //调用方式改进版本
        //useCat(c);
        //useCat(c2);
        //useCat(c3);
        
        //AnimalTool.useCat(c);
        //AnimalTool.useCat(c2);
        //AnimalTool.useCat(c3);
        
        AnimalTool.useAnimal(c);
        AnimalTool.useAnimal(c2);
        AnimalTool.useAnimal(c3);
        System.out.println("--------------");
        
        //我喜欢狗
        Dog d = new Dog();
        Dog d2 = new Dog();
        Dog d3 = new Dog();
        //AnimalTool.useDog(d);
        //AnimalTool.useDog(d2);
        //AnimalTool.useDog(d3);
        AnimalTool.useAnimal(d);
        AnimalTool.useAnimal(d2);
        AnimalTool.useAnimal(d3);
        System.out.println("--------------");
        
        //我喜欢宠物猪
        //定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用
        Pig p = new Pig();
        Pig p2 = new Pig();
        Pig p3 = new Pig();
        //AnimalTool.usePig(p);
        //AnimalTool.usePig(p2);
        //AnimalTool.usePig(p3);
        AnimalTool.useAnimal(p);
        AnimalTool.useAnimal(p2);
        AnimalTool.useAnimal(p3);
        System.out.println("--------------");
        
        //我喜欢宠物狼,老虎,豹子...
        //定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用
        //前面几个必须写,我是没有意见的
        //但是,工具类每次都改,麻烦不
        //我就想,你能不能不改了
        //太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢?
        //改用另一种解决方案。
        
    }
    
    /*
    //调用猫的功能
    public static void useCat(Cat c) {
        c.eat();
        c.sleep();
    }
    
    //调用狗的功能
    public static void useDog(Dog d) {
        d.eat();
        d.sleep();
    }
    */
}

【多态的弊端】

  不能使用子类的特有功能。

class Fu {
    public void show() {
        System.out.println("show fu");
    }
}

class Zi extends Fu {
    public void show() {
        System.out.println("show zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }

}

class DuoTaiDemo3 {
    public static void main(String[] args) {
        //测试
        Fu f = new Zi();
        f.show();
        //f.method();//报错
    }
}

  我就想使用子类的特有功能?行不行?行。

  怎么用呢?

  A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)

  B:把父类的引用强制转换为子类的引用。(向下转型)

1.5 多态中的转型问题

【向上转型】

  从子到父

  父类引用指向子类对象

【向下转型】

  从父到子

  父类引用转为子类对象

class Fu {
    public void show() {
        System.out.println("show fu");
    }
}

class Zi extends Fu {
    public void show() {
        System.out.println("show zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }

}

class DuoTaiDemo4 {
    public static void main(String[] args) {
        //测试
        //向上转型
        Fu f = new Zi();
        f.show();//show zi
        //f.method();
        
        //创建子类对象
        //Zi z = new Zi();
        //z.show();
        //z.method();
        
        //你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢?
        //向下转型
        Zi z = (Zi)f;//要求该f必须是能够转换为Zi的。
        z.show();//show zi
        z.method();//method zi
    }
}

  注意:在多态的向下转型中容易出现ClassCastException——类型转换异常

class Animal {
    public void eat(){}
}

class Dog extends Animal {
    public void eat() {}
    
    public void lookDoor() {
    
    }
}

class Cat extends Animal {
    public void eat() {
    
    }
    
    public void playGame() {
        
    }
}

class AnimalDemo {
    public static void main(String[] args) {
        //内存中的是狗
        Animal a = new Dog();
        a.eat();
        //a.lookDoor();//报错
        
        Dog d = (Dog)a;
        d.eat();
        d.lookDoor();
        
        //内存中是猫
        a = new Cat();
        a.eat();
        //a.playGame();//报错
        
        Cat c = (Cat)a;
        c.eat();
        c.playGame();
        
        //内存中是猫
        Dog dd = (Dog)a; //ClassCastException
    }
}

1.6 多态的成员访问特点及转型的理解

class 孔子爹 {
    public int age = 40;
    
    public void teach() {
        System.out.println("讲解JavaSE");
    }
}

class 孔子 extends 孔子爹 {
    public int age = 20;
    
    public void teach() {
        System.out.println("讲解论语");
    }
    
    public void playGame() {
        System.out.println("英雄联盟");
    }
}

  Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了,但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹。

//向上转型
孔子爹 k爹 = new 孔子();
//到人家那里去了
System.out.println(k爹.age); //40
k爹.teach(); //讲解论语
//k爹.playGame(); //这是儿子才能做的

  讲完了,下班回家了。脱下爹的装备,换上自己的装备

//向下转型
孔子 k = (孔子) k爹; 
System.out.println(k.age); //20
k.teach(); //讲解论语
k.playGame(); //英雄联盟

1.7 多态练习

【猫狗案例】

class Animal {
    public void eat(){
        System.out.println("吃饭");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃肉");
    }
    
    public void lookDoor() {
        System.out.println("狗看门");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
    
    public void playGame() {
        System.out.println("猫捉迷藏");
    }
}

class DuoTaiTest {
    public static void main(String[] args) {
        //定义为狗
        Animal a = new Dog();
        a.eat();
        System.out.println("--------------");
        //还原成狗
        Dog d = (Dog)a;
        d.eat();
        d.lookDoor();
        System.out.println("--------------");
        //变成猫
        a = new Cat();
        a.eat();
        System.out.println("--------------");
        //还原成猫
        Cat c = (Cat)a;
        c.eat();
        c.playGame();
        System.out.println("--------------");
        
        //演示错误的内容
        //Dog dd = new Animal();
        //Dog ddd = new Cat();
        //ClassCastException
        //Dog dd = (Dog)a;
    }
}    

【看程序写结果】

class A {
    public void show() {
        show2();
    }
    public void show2() {
        System.out.println("我");
    }
}
class B extends A {
    /*
    public void show() {
        show2();
    }
    */

    public void show2() {
        System.out.println("爱");
    }
}
class C extends B {
    public void show() {
        super.show();
    }
    public void show2() {
        System.out.println("你");
    }
}
public class DuoTaiTest4 {
    public static void main(String[] args) {
        A a = new B();
        a.show();//
        
        B b = new C();
        b.show();//
    }
}

继承的时候:

  子类中有和父类中一样的方法,叫重写。
  子类中没有父亲中出现过的方法,方法就被继承过来了。

二、抽象类

2.1 抽象类概述

  回想前面我们的猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实这是不对的。为什么呢?因为,我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。 所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。

2.2 抽象类的特点

  1. 抽象类和抽象方法必须用abstract关键字修饰
    格式
    abstract class 类名 {}
    public abstract void eat();
  2. 抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
  3. 抽象类不能实例化
    因为它不是具体的。那么,抽象类如何实例化呢?
    按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。Animal a = new Cat();
    抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
    用于子类访问父类数据的初始化
  4. 抽象的子类
    a:如果不想重写抽象方法,该子类是一个抽象类。
    b:重写所有的抽象方法,这个时候子类是一个具体的类。

  演示案例:

abstract class Animal {
    //抽象方法
    //public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
    public abstract void eat();
    
    public Animal(){}
}

//子类是抽象类
abstract class Dog extends Animal {}

//子类是具体类,重写抽象方法
class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

class AbstractDemo {
    public static void main(String[] args) {
        //创建对象
        //Animal是抽象的; 无法实例化
        //Animal a = new Animal();
        //通过多态的方式
        Animal a = new Cat();
        a.eat();
    }
}

2.3 抽象类的成员特点

【成员变量】

  既可以是变量,也可以是常量。

【构造方法】

  有构造方法,但是不能实例化。那么,构造方法的作用是什么呢?
  用于子类访问父类数据的初始化

【成员方法】

  可以有抽象方法:限定子类必须完成某些动作。
  也可以有非抽象方法:子类继承的事情,提高代码复用性。

abstract class Animal {
    public int num = 10;
    public final int num2 = 20;

    public Animal() {}
    
    public Animal(String name,int age){}
    
    public abstract void show();
    
    public void method() {
        System.out.println("method");
    }
}

class Dog extends Animal {
    public void show() {
        System.out.println("show Dog");
    }
}

class AbstractDemo2 {
    public static void main(String[] args) {
        //创建对象
        Animal a = new Dog();
        a.num = 100;
        System.out.println(a.num);//100
        //a.num2 = 200;
        System.out.println(a.num2);//20
        System.out.println("--------------");
        a.show();//show Dog
        a.method();//method
    }
}

2.4 抽象类练习

【猫狗案例】

  具体事物:猫,狗

  共性:姓名,年龄,吃饭

/*
    分析:从具体到抽象
        猫:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭(猫吃鱼)
            
        狗:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭(狗吃肉)
            
        因为有共性的内容,所以就提取了一个父类。动物。
        但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的,
        而方法是抽象的类,类就必须定义为抽象类。
        
        抽象动物类:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭();
    
    实现:从抽象到具体
        动物类:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭();
            
        狗类:
            继承自动物类
            重写吃饭();
            
        猫类:
            继承自动物类
            重写吃饭();
*/
//定义抽象的动物类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //定义一个抽象方法
    public abstract void eat();
}

//定义具体的狗类
class Dog extends Animal {
    public Dog() {}
    
    public Dog(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//定义具体的猫类
class Cat extends Animal {
    public Cat() {}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//测试类
class AbstractTest {
    public static void main(String[] args) {
        //测试狗类
        //具体类用法
        //方式1:
        Dog d = new Dog();
        d.setName("旺财");
        d.setAge(3);
        System.out.println(d.getName()+"---"+d.getAge());
        d.eat();
        //方式2:
        Dog d2 = new Dog("旺财",3);
        System.out.println(d2.getName()+"---"+d2.getAge());
        d2.eat();
        System.out.println("---------------------------");
        
        Animal a = new Dog();
        a.setName("旺财");
        a.setAge(3);
        System.out.println(a.getName()+"---"+a.getAge());
        a.eat();
        
        Animal a2 = new Dog("旺财",3);
        System.out.println(a2.getName()+"---"+a2.getAge());
        a2.eat();

    }
}

【学生案例】

  具体事务:基础班学员,就业班学员

  共性:姓名,年龄,班级,学习,吃饭

/*
    分析:
        基础班学员
            成员变量:姓名,年龄,班级
            成员方法:学习,吃饭
        就业班学员
            成员变量:姓名,年龄,班级
            成员方法:学习,吃饭
            
        得到一个学员类。
            成员变量:姓名,年龄,班级
            成员方法:学习,吃饭
            
    实现:
        学员类
        基础班学员
        就业班学员
*/
//定义抽象学员类
abstract class Student {
    //姓名
    private String name;
    //年龄
    private int age;
    //班级
    private String grand;
    
    public Student() {}
    
    public Student(String name,int age,String grand) {
        this.name = name;
        this.age = age;
        this.grand = grand;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public String getGrand() {
        return grand;
    }
    
    public void setGrand(String grand) {
        this.grand = grand;
    }
    
    //学习
    public abstract void study();
    
    //吃饭
    public void eat() {
        System.out.println("学习累了,就该吃饭");
    }
}

//具体基础班学员类
class BasicStudent extends Student {
    public BasicStudent() {}
    
    public BasicStudent(String name,int age,String grand) {
        super(name,age,grand);
    }
    
    public void study() {
        System.out.println("基础班学员学习的是JavaSE");
    }
}

//具体就业班学员类
class WorkStudent extends Student {
    public WorkStudent() {}
    
    public WorkStudent(String name,int age,String grand) {
        super(name,age,grand);
    }
    
    public void study() {
        System.out.println("就业班学员学习的是JavaEE");
    }
}

class AbstractTest3 {
    public static void main(String[] args) {
        //我仅仅测试基础班学员
        //按照多态的方式测试
        Student s = new BasicStudent();
        s.setName("林青霞");
        s.setAge(27);
        s.setGrand("1111");
        System.out.println(s.getName()+"---"+s.getAge()+"---"+s.getGrand());
        s.study();
        s.eat();
        System.out.println("--------------");
        
        s = new BasicStudent("武鑫",48,"1111");
        System.out.println(s.getName()+"---"+s.getAge()+"---"+s.getGrand());
        s.study();
        s.eat();
        
    }
}

【员工案例】

  假如我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

/*
    分析:
        普通员工类
            成员变量:姓名、工号以及工资。
            成员方法:工作
        经理类:
            成员变量:姓名、工号以及工资,奖金属性
            成员方法:工作
            
    实现:
        员工类:
        普通员工类:
        经理类:
*/
//定义员工类
abstract class Employee {
    //姓名、工号以及工资
    private String name;
    private String id;
    private int salary;
    
    public Employee() {}
    
    public Employee(String name,String id,int salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public int getSalary() {
        return salary;
    }
    
    public void setSalary(int salary) {
        this.salary = salary;
    }
    
    //工作
    public abstract void work();
}

//普通员工类
class Programmer extends Employee {
    public Programmer(){}
    
    public Programmer(String name,String id,int salary) {
        super(name,id,salary);
    }
    
    public void work() {
        System.out.println("按照需求写代码");
    }
}

//经理类
class Manager extends Employee {
    //奖金
    private int money; //bonus 奖金

    public Manager(){}
    
    public Manager(String name,String id,int salary,int money) {
        super(name,id,salary);
        this.money = money;
    }
    
    public void work() {
        System.out.println("跟客户谈需求");
    }
    
    public int getMoney() {
        return money;
    }
    
    public void setMoney(int money) {
        this.money = money;
    }
}

class AbstractTest4 {
    public static void main(String[] args) {
        //测试普通员工
        Employee emp = new Programmer();
        emp.setName("林青霞");
        emp.setId("czbk001");
        emp.setSalary(18000);
        System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary());
        emp.work();
        System.out.println("-------------");
        emp = new Programmer("林青霞","czbk001",18000);
        System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary());
        emp.work();
        System.out.println("-------------");
        
        /*
        emp = new Manager();
        emp.setName("刘意");
        emp.setId("czbk002");
        emp.setSalary(8000);
        emp.setMoney(2000);
        */
        //由于子类有特有的内容,所以我们用子类来测试
        Manager m = new Manager();
        m.setName("刘意");
        m.setId("czbk002");
        m.setSalary(8000);
        m.setMoney(2000);
        System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney());
        m.work();
        System.out.println("-------------");
        
        //通过构造方法赋值
        m = new Manager("刘意","czbk002",8000,2000);
        System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney());
        m.work();
    }
}

2.5 抽象类的补充问题

【补充问题一】

  一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?

  答:可以。意义是:不让创建对象

【补充问题二】

  abstract不能和哪些关键字共存?

  private:冲突
  final:冲突
  static :意义

abstract class Fu {
    //public abstract void show();
    //非法的修饰符组合: abstract和private
    //private abstract void show();
    
    //非法的修饰符组合
    //final abstract void show();    
    
    //非法的修饰符组合
    static abstract void show();
    
    public static void method() {
        System.out.println("method");
    }
}

class Zi extends Fu {
    public void show() {}
}

class AbstractDemo3 {
    public static void main(String[] args) {
        Fu.method();
    }
}

三、接口

3.1 接口概述

  继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。

3.2 接口的特点

  1. 接口用关键字interface表示
    interface 接口名 {}
  2. 类实现接口用implements表示
    class 类名 implements 接口名 {}
  3. 接口不能实例化
    那么,接口如何实例化呢?
    按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。
  4. 接口的子类
    可以是抽象类。但是意义不大。
    可以是具体类。要重写接口中的所有抽象方法。(推荐方案)

  由此可见,多态一共有3种类型:

  A:具体类多态(几乎没有)
  B:抽象类多态(常用)
  C:接口多态(最常用)

//定义动物培训接口
interface AnimalTrain {
    public abstract void jump();
}

//抽象类实现接口
abstract class Dog implements AnimalTrain {
}

//具体类实现接口
class Cat implements AnimalTrain {
    public void jump() {
        System.out.println("猫可以跳高了");
    }
}

class InterfaceDemo {
    public static void main(String[] args) {
        //AnimalTrain是抽象的; 无法实例化
        //AnimalTrain at = new AnimalTrain();
        //at.jump();
        
        AnimalTrain at = new Cat();
        at.jump();
    }
}

3.3 接口成员特点

  • 成员变量:只能是常量,并且是静态的。默认修饰符:public static final
  • 构造方法:接口没有构造方法。因为接口主要是扩展功能的,而没有具体存在

  • 成员方法:只能是抽象方法。默认修饰符:public abstract
interface Inter {
    public int num = 10;
    public final int num2 = 20;
    public static final int num3 = 30;
    
    //错误: 需要<标识符>
    //public Inter() {}
    
    //接口方法不能带有主体
    //public void show() {}

    //abstract void show(); //默认public
    public void show(); //默认abstract
}


//所有类都默认继承Object 类
//接口名+Impl这种格式是接口的实现类格式
class InterImpl implements Inter {
    public InterImpl() {
        super();
    }
    
    public void show() {}
}

//测试类
class InterfaceDemo2 {
    public static void main(String[] args) {
        //创建对象
        Inter i = new InterImpl();
        System.out.println(i.num);
        System.out.println(i.num2);
        //i.num = 100;
        //i.num2 = 200;
        //System.out.println(i.num); //无法为最终变量num分配值
        //System.out.println(i.num2);//无法为最终变量num2分配值
        System.out.println(Inter.num);
        System.out.println(Inter.num2);
        System.out.println("--------------");
    }
}

3.4 类与类,类与接口,接口与接口的关系

【类与类】

   继承关系,只能单继承,可以多层继承。

【类与接口】

  实现关系,可以单实现,也可以多实现。并且还可以在继承一个类的同时实现多个接口。

【接口与接口】

  继承关系,可以单继承,也可以多继承。

interface Father {
    public abstract void show();
}

interface Mother {
    public abstract void show2();
}

interface Sister extends Father,Mother {

}

//class Son implements Father,Mother //多实现
class Son extends Object implements Father,Mother {
    public void show() {
        System.out.println("show son");
    }
    
    public void show2() {
        System.out.println("show2 son");
    }
}

class InterfaceDemo3 {
    public static void main(String[] args) {
        //创建对象
        Father f = new Son();
        f.show();
        //f.show2(); //报错
    
        Mother m = new Son();
        //m.show(); //报错
        m.show2();
    }
}

3.5 抽象类和接口的区别

【成员区别】

  抽象类:
    成员变量:可以变量,也可以常量
    构造方法:有
    成员方法:可以抽象,也可以非抽象
  接口:
    成员变量:只可以常量
    成员方法:只可以抽象

【关系区别】

  类与类
    继承,单继承
  类与接口
    实现,单实现,多实现
  接口与接口
    继承,单继承,多继承

【设计理念区别】

  抽象类:被继承体现的是”is a”的关系。抽象类中定义的是该继承体系的共性功能。
  接口:被实现体现的是”like a”的关系。接口中定义的是该继承体系的扩展功能。

3.6 接口的练习

【猫狗案例】——加入跳高的额外功能

/*
    分析:从具体到抽象
        猫:
            姓名,年龄
            吃饭,睡觉
        狗:
            姓名,年龄
            吃饭,睡觉
            
        由于有共性功能,所以,我们抽取出一个父类:
        动物:
            姓名,年龄
            吃饭();
            睡觉(){}
            
        猫:继承自动物
        狗:继承自动物
        
        跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
        接口:
            跳高
            
        部分猫:实现跳高
        部分狗:实现跳高
    实现;
        从抽象到具体
        
    使用:
        使用具体类
*/
//定义跳高接口
interface Jumpping {
    //跳高功能
    public abstract void jump();
}

//定义抽象类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //吃饭();
    public abstract void eat();
    
    //睡觉(){}
    public void sleep() {
        System.out.println("睡觉觉了");
    }
}

//具体猫类
class Cat extends Animal {
    public Cat(){}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//具体狗类
class Dog extends Animal {
    public Dog(){}
    
    public Dog(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
    public JumpCat() {}
    
    public JumpCat(String name,int age) {
        super(name,age);
    }

    public void jump() {
        System.out.println("跳高猫");
    }
}

//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
    public JumpDog() {}
    
    public JumpDog(String name,int age) {
        super(name,age);
    }

    public void jump() {
        System.out.println("跳高狗");
    }
}

class InterfaceTest {
    public static void main(String[] args) {
        //定义跳高猫并测试
        JumpCat jc = new JumpCat();
        jc.setName("哆啦A梦");
        jc.setAge(3);
        System.out.println(jc.getName()+"---"+jc.getAge());
        jc.eat();
        jc.sleep();
        jc.jump();
        System.out.println("-----------------");
        
        JumpCat jc2 = new JumpCat("加菲猫",2);
        System.out.println(jc2.getName()+"---"+jc2.getAge());
        jc2.eat();
        jc2.sleep();
        jc2.jump();
    }
}

【老师和学生案例】——加入抽烟的额外功能

/*
    分析:从具体到抽象
        老师:姓名,年龄,吃饭,睡觉
        学生:姓名,年龄,吃饭,睡觉
        
        由于有共性功能,我们提取出一个父类,人类。
        
        人类:
            姓名,年龄
            吃饭();
            睡觉(){}
            
        抽烟的额外功能不是人或者老师,或者学生一开始就应该具备的,所以,我们把它定义为接口
        
        抽烟接口。

        部分老师抽烟:实现抽烟接口
        部分学生抽烟:实现抽烟接口
        
    实现:从抽象到具体
        
    使用:具体
*/
//定义抽烟接口
interface Smoking {
    //抽烟的抽象方法
    public abstract void smoke();
}

//定义抽象人类
abstract class Person {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Person() {}
    
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //吃饭();
    public abstract void eat();
    
    //睡觉(){}
    public void sleep() {
        System.out.println("睡觉觉了");
    }
}

//具体老师类
class Teacher extends Person {
    public Teacher() {}
    
    public Teacher(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("吃大白菜");
    }
}

//具体学生类
class Student extends Person {
    public Student() {}
    
    public Student(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("吃红烧肉");
    }
}

//抽烟的老师
class SmokingTeacher extends Teacher implements Smoking {
    public SmokingTeacher() {}
    
    public SmokingTeacher(String name,int age) {
        super(name,age);
    }

    public void smoke() {
        System.out.println("抽烟的老师");
    }
}

//抽烟的学生
class SmokingStudent extends Student implements Smoking {
    public SmokingStudent() {}
    
    public SmokingStudent(String name,int age) {
        super(name,age);
    }

    public void smoke() {
        System.out.println("抽烟的学生");
    }
}

class InterfaceTest2 {
    public static void main(String[] args) {
        //测试学生
        SmokingStudent ss = new SmokingStudent();
        ss.setName("林青霞");
        ss.setAge(27);
        System.out.println(ss.getName()+"---"+ss.getAge());
        ss.eat();
        ss.sleep();
        ss.smoke();
        System.out.println("-------------------");
        
        SmokingStudent ss2 = new SmokingStudent("刘意",30);
        System.out.println(ss2.getName()+"---"+ss2.getAge());
        ss2.eat();
        ss2.sleep();
        ss2.smoke();
    }
}

【教练和运动员案例】

  乒乓球运动员和篮球运动员。乒乓球教练和篮球教练。  

  为了出国交流,跟乒乓球相关的人员都需要学习英语。

  请用所学知识:分析,这个案例中有哪些抽象类,哪些接口,哪些具体类。

//定义一个说英语的接口
interface SpeakEnglish {
    //说英语
    public abstract void speak();
}

//定义人的抽象类
abstract class Person {
    private String name;
    private int age;
    
    public Person() {}
    
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //睡觉
    public void sleep() {
        System.out.println("人都是要睡觉的");
    }
    
    //吃饭
    public abstract void eat();
}

//定义运动员抽象类
abstract class Player extends Person {
    public Player() {}
    
    public Player(String name,int age) {
        super(name,age);
    }
    
    //学习
    public abstract void study();
}

//定义教练抽象类
abstract class Coach extends Person {
    public Coach() {}
    
    public Coach(String name,int age) {
        super(name,age);
    }
    
    //
    public abstract void teach();
}

//定义乒乓球运动员具体类
class PingPangPlayer extends Player implements SpeakEnglish {
    public PingPangPlayer(){}
    
    public PingPangPlayer(String name,int age) {
        super(name,age);
    }
    
    //
    public void eat() {
        System.out.println("乒乓球运动员吃大白菜,喝小米粥");
    }
    
    //学习
    public void study() {
        System.out.println("乒乓球运动员学习如何发球和接球");
    }
    
    //说英语
    public void speak() {
        System.out.println("乒乓球运动员说英语");
    }
}

//定义篮球运动员具体类
class BasketballPlayer extends Player {
    public BasketballPlayer(){}
    
    public BasketballPlayer(String name,int age) {
        super(name,age);
    }
    
    //
    public void eat() {
        System.out.println("篮球运动员吃牛肉,喝牛奶");
    }
    
    //学习
    public void study() {
        System.out.println("篮球运动员学习如何运球和投篮");
    }
}

//定义乒乓球教练具体类
class PingPangCoach extends Coach implements SpeakEnglish {
    public PingPangCoach(){}
    
    public PingPangCoach(String name,int age) {
        super(name,age);
    }
    
    //
    public void eat() {
        System.out.println("乒乓球教练吃小白菜,喝大米粥");
    }
    
    //
    public void teach() {
        System.out.println("乒乓球教练教如何发球和接球");
    }
    
    //说英语
    public void speak() {
        System.out.println("乒乓球教练说英语");
    }
}

//定义篮球教练具体类
class BasketballCoach extends Coach {
    public BasketballCoach(){}
    
    public BasketballCoach(String name,int age) {
        super(name,age);
    }
    
    //
    public void eat() {
        System.out.println("篮球教练吃羊肉,喝羊奶");
    }
    
    //
    public void teach() {
        System.out.println("篮球教练教如何运球和投篮");
    }
}

class InterfaceDemo {
    public static void main(String[] args) {
        //测试运动员(乒乓球运动员和篮球运动员)
        //乒乓球运动员
        PingPangPlayer ppp = new PingPangPlayer();
        ppp.setName("王浩");
        ppp.setAge(33);
        System.out.println(ppp.getName()+"---"+ppp.getAge());
        ppp.eat();
        ppp.sleep();
        ppp.study();
        ppp.speak();
        System.out.println("----------------");
        //通过带参构造给数据(留给你们)
        
        //篮球运动员
        BasketballPlayer bp = new BasketballPlayer();
        bp.setName("姚明");
        bp.setAge(34);
        System.out.println(bp.getName()+"---"+bp.getAge());
        bp.eat();
        bp.sleep();
        bp.study();
        //bp.speak(); //没有该方法
        
    }
}

 

posted @ 2019-05-08 11:36  yi0123  阅读(522)  评论(0编辑  收藏  举报