面向对象编程-多态

多态基本介绍

方法或对象有多种形态,是面向对象编程的第三大特征,多态是建立在封装和继承基础上的

多态的具体体现

1.方法的多态

package com.hsp.polyorphic.learning;

public class PloyMethod {
    public static void main(String[] args) {
        //我们通过不同的参数个数去调用sum方法,就回去调用不同的方法
        //因此对sum方法来说,就是多种状态的体现
        A a = new A();
        //方法的重载体现出多态
        System.out.println(a.sum(10,20));
        System.out.println(a.sum(10,20,30));
//        方法的重写体现多态
        B b = new B();
        a.say();
        b.say();
    }
}
class B  {//父类
    public void say(){
        System.out.println("B say()方法被调用");
    }
}
class A extends B {
    //方法的重载体现出多态
    public int sum(int n1,int n2) {
        return n1 + n2;
    }
    public int sum(int n1,int n2,int n3){
        return n1 + n2 + n3;
    }

}

2.对象的多态(核心)

  • 一个对象的编译类型运行类型可以不一致
  • 编译类型在定义对象时,就确定了,不能改变
  • 运行类型是可以变化的
  • 编译类型看定义时=号的左边,运行类型看=号的右边

Animail.java

package com.hsp.polyorphic.test;

public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Cat.java

package com.hsp.polyorphic.learning.objectpoly;

public class Cat extends Animal {
    public void cry() {
        System.out.println("Cat cry() 小猫");
    }
}

Dog.java

package com.hsp.polyorphic.learning.objectpoly;

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

PolyObject.java

package com.hsp.polyorphic.learning.objectpoly;

public class PolyObject {
    public static void main(String[] args) {
        //体验对象多态特带你
        // animal编译类型是Animal,运行类型是Dog
        Animal animal = new Dog();
        animal.cry();//因为运行时,这是就执行到改行时,animal运行类型是dog
        //所以这个cry 就是dog的cry
//        Dog cry()小狗
        animal = new Cat();
        animal.cry();
        //Cat cry() 小猫
    }
}

多态使用细节

多态注意事项和细节讨论

  1. 本质:父类的引用指向了子类的对象
  2. 语法:父类类型 引用名 = new 子类类型();
  3. 特点:编译类型看左边,运行类型看右边
  4. 可以调用父类种的所有成员(需遵守访问权限)
  5. 不能调用子类种特有成员
  6. 最终运行效果看子类的具体实现

Animal.java

package com.hsp.polyorphic.detail;

public class Animal {
    String name = "动物";
    public void sleep(){
        System.out.println("睡觉");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello,你好");
    }
}

Cat.java

package com.hsp.polyorphic.detail;

public class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫捉老鼠");
    }
}

Detail.java

package com.hsp.polyorphic.detail;

public class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫捉老鼠");
    }
}

多态的向下转型

  • 语法:子类类型 引用名 = (子类类型) 父类引用;

  • 只能强转父类的引用,不能强转父类的对象

  • 要求父类的引用必须指向的是当前目标类型的对象

  • 当向下转型后,可以调用子类类型中的所有成员

package com.hsp.polyorphic.detail;

public class PolyDetail {
    public static void main(String[] args) {
        Animal animal = new Cat();
        // 向上转型,父类的引用指向了子类的对象
        //可以调用父类中的所有成员
        //因为在编译阶段,能调用哪些成员,是由编译类型来决定的
        animal.eat();//猫吃鱼
        animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡觉
        //animal.catchMouse();错误
        //最终运行效果看子类的具体实现,即调用方法时,按照从子类开始查找方法

        //希望可以调用Cat 的catchMouse 方法
        //多态的向下转型
        //语法:子类类型 引用名 = (子类类型) 父类引用;
        // cat的编译类型是Cat,运行类型是Cat

        Cat cat = (Cat) animal;
        cat.catchMouse();
        //要求父类的引用必须指向的是当前目标类型的对象

    }
}

属性重写问题

属性没有重写之说,属性的值看编译类型:向上转型看编译类型

package com.hsp.polyorphic.detail;

public class PolyDetail {
    public static void main(String[] args) {
        Base base = new Sub(); //向上转型
        System.out.println(base.count); //看编译类型 10
        Sub sub = new Sub();
        System.out.println(sub.count); //20
    }
}
class Base {
    int count = 10;
}
class Sub extends Base {
    int count = 20;
}




instanceOf 比较运算符

instanceOf比较操作符,用于判断对象的运行类型是否为XX类型的子类型

参考下面的

package com.hsp.polyorphic.detail1;

public class deatil {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof AA);//true
        System.out.println(bb instanceof BB);//true
        AA aa = new BB(); //
        //编译类型是AA,运行类型是BB
        System.out.println(aa instanceof AA);//true
        System.out.println(aa instanceof BB);//true
        //instanceOf比较操作符,用于判断对象的运行类型是否为XX类型的子类型
    }
}
class AA { //父类

}
class BB extends AA{ //子类

}

image-20221121160704056

动态绑定机制

1.当调用对象方法的时候,该方法和该对象的内存地址/运行类型绑定

2.当调用对象属性时,没有动态绑定和机制,哪里声明,哪里使用

多态的应用

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类型

应用实例:现有一个继承结构如下:要求创建一个Person对象,2个Student对象和2个Teacher对象,统一放在数组中,并调用say方法

image-20221121170850063

Person.java

package com.hsp.polyorphic.Array;

public class Person {
    private String name;
    private int age;

    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 String say() {
        return "name = " + name + "\t" + "age = " + age;
    }
}

Student.java

package com.hsp.polyorphic.Array;

public class Student extends Person {
    private double score;

    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
    //重写父类的say方法

    @Override
    public String say() {
        return super.say() + " " + "score = " + score;
    }
}

Teacher.java

package com.hsp.polyorphic.Array;

public class Teacher extends Person {
    private double salary;

    public Teacher(String name, int age, double salary) {
        super(name, age);
        this.salary = salary;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String say() {
        return super.say() + " " + "salary = " + salary;
    }
}

PloyArray.java

package com.hsp.polyorphic.Array;

public class PloyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("hack", 20);
        persons[1] = new Student("ajcl", 15, 100);
        persons[2] = new Student("meow", 17, 70);
        persons[3] = new Teacher("hc", 30, 10000);
        persons[4] = new Teacher("jf", 32, 12000);
        //遍历多态数组,调用say
        for (int i = 0; i < persons.length; i++) {
            //person[i]的编译类型是Person,运行类型是根据实际情况由JVM来判断的
            System.out.println(persons[i].say());
        }


    }
}

如果Teacher类和Student类有自己的方法该怎么办呢?

PloyArray.java

package com.hsp.polyorphic.Array;

public class PloyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("hack", 20);
        persons[1] = new Student("ajcl", 15, 100);
        persons[2] = new Student("meow", 17, 70);
        persons[3] = new Teacher("hc", 30, 10000);
        persons[4] = new Teacher("jf", 32, 12000);
        //遍历多态数组,调用say
        for (int i = 0; i < persons.length; i++) {
            //person[i]的编译类型是Person,运行类型是根据实际情况由JVM来判断的
            System.out.println(persons[i].say());
            if(persons[i] instanceof Student) {
                ((Student)persons[i]).study();
            }
            else if(persons[i] instanceof Teacher) {
                ((Teacher)persons[i]).teach();
            }
        }


    }
}

Student.java

package com.hsp.polyorphic.Array;

public class Student extends Person {
    private double score;

    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
    //重写父类的say方法

    @Override
    public String say() {
        return super.say() + " " + "score = " + score;
    }
    public void study(){
        System.out.println("学生" + getName() + "正在学习");
    }
}

Teacher.java

package com.hsp.polyorphic.Array;

public class Student extends Person {
    private double score;

    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
    //重写父类的say方法

    @Override
    public String say() {
        return super.say() + " " + "score = " + score;
    }
    public void study(){
        System.out.println("学生" + getName() + "正在学习");
    }
}

Person.java

package com.hsp.polyorphic.Array;

public class Person {
    private String name;
    private int age;

    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 String say() {
        return "name = " + name + "\t" + "age = " + age;
    }
}

多态参数

方法定义的形参类型为父类类型,实参类型允许为子类类型

image-20221121172035216

Employee.java

package com.hsp.polyorphic.parameter;

public class Employee {
    private String name;
    private double salary;


    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    public double getAnnual() {
        return salary * 12;
    }
}

NormalEmployee.java

package com.hsp.polyorphic.parameter;

public class NormalEmployee extends Employee{
    public NormalEmployee(String name, double salary) {
        super(name, salary);
    }
    public void work(){
        System.out.println("普通员工" + getName() + "正在工作中");
    }

    @Override
    public double getAnnual() {
        return super.getAnnual();
    }
}

Manager.java

package com.hsp.polyorphic.parameter;

public class Manager extends Employee {
    private double bonus;

    public void manage() {
        System.out.println("经理" + getName() + "正在管理..");
    }

    public Manager(String name, double salary, double bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    @Override
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}

Test.java

package com.hsp.polyorphic.parameter;

public class Test {
    public static void main(String[] args) {
        NormalEmployee tom = new NormalEmployee("tom", 3000);
        Manager meowrain = new Manager("meowrain", 5000, 20000);
        showEmpAnnal(meowrain);
        showEmpAnnal(tom);
        testWork(meowrain);
        testWork(tom);
    }

    public static void showEmpAnnal(Employee e) {
        System.out.println(e.getAnnual());
    }
    public static void testWork(Employee e){
        if(e instanceof NormalEmployee){
            ((NormalEmployee) e).work();

        }else if(e instanceof Manager){
            ((Manager) e).manage();
        }
    }
}