zoukankan      html  css  js  c++  java
  • 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(); //没有该方法
            
        }
    }
  • 相关阅读:
    内存溢出异常
    Java堆中的对象
    运行时数据区域
    字符串常量池
    自己编译JDK
    @PathVariable注解详解
    spring容器监听器
    redis和spring整合
    Redis安装、启动、关闭
    HDU3974 Assign the task
  • 原文地址:https://www.cnblogs.com/yft-javaNotes/p/10829845.html
Copyright © 2011-2022 走看看