多态

多态的基础:

多态可以解决代码的复用性不高,不利于代码维护的问题

多态只能用于方法的多态,不能用于属性的

多态是建立在封装和继承的基础之上的

多态也叫多种状态,指方法或对象具有多种状态;多态能体现在以下这几个方面:

  • 方法重载的多态

    • public class Demo01 {
          public static void main(String[] args) {
              A a = new A();
              //根据参数列表的不同,调用了A类中不同的sum,这就是方法重载的多态
              System.out.println(a.sum(1,2));
              System.out.println(a.sum(1,2,3));
          }
      }
      class A  {
          //sum构成了方法的重载
          public int sum(int a,int b){
              return a+b;
          }
          public int sum(int a,int b,int c){
              return a+b+c;
          }
      }
      
      
  • 方法的重写构成多态

    • public class Demo01 {
          public static void main(String[] args) {
              A a = new A();
              B b = new B();
              //虽然方法都是say,但是引用类型不一样,a重写b的say,这就是方法的多态
              a.say();   //结果是A  的say()
              b.say();   //结果是B  的say()
          }
      }
      class B{
          public void say(){
              System.out.println("B  的say()");
          }
      }
      class A extends B{
          public void say(){
              System.out.println("A  的say()");
          }
      }
      
      

对象的多态:

多态呢就是父类可以引用指向子类的对象方法

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

可以通过getClass()来查看运行类型

如:

Animal animal = new Dog();  //animal的编译类型是Animal,运行类型是Dog
animal = new Cat();    //animal的运行类型变成了Cat,编译类型仍然是Animal
//通俗的理解:一只Dog一生(new)下来就是animal,一只Cat一生(new)下来也是animal,animal可以对于不同的形态,但是animal这个词被人们(敲代码的你)定义后(Animal animal)就永远不可能改变

案例:

public class test {
    public static void main(String[] args) {
        
        //animal的编译类型是Animal 运行类型是Animal
        Animal animal = new Animal();
        animal.cry();   //结果是  动物 在叫
        
        //animal的编译类型是Animal 运行类型是Dog
        animal = new Dog();
        animal.cry();   //结果是  Dog在叫
        
        //animal的编译类型是Animal 运行类型是Cat
        animal = new Cat();
        animal.cry();   //结果是  Cat在叫
        //结论:同样是cry()方法,但是因为运行类型不同,结果不同,这就是对象的多态
    }
}
class Animal{
    public void cry(){
        System.out.println("动物 在叫");
    }
}
class Dog extends Animal{
    public void cry() {
        System.out.println("Dog在叫");
    }
}
class Cat extends Animal{
    public void cry() {
        System.out.println("Cat在叫");
    }
}

多态的小细节:

多态的前提:两个对象(类)存在继承关系

向上转型:

  • 本质:父类的引用指向了子类的对象
  • 语法:父类类型 引用名 =new 子类类型();
  • 特点:编译类型看左边,运行类型看右边
    • 可以调用父类的所有成员(需遵守访问权限)
    • 不能调用子类中特有的成员 因为在编译阶段能调用哪些成员,是由编译类型来决定的
    • 最终运行效果看子类(运行类型)的具体实现,即调用方法时,按照从子类(运行类型)开始查找方法,然后调用,规则和前面的方法调用规则一致

(编译阶段是由javac来实现的,只关心编译类型,不关心运行类型;但是运行起来就由java来实现,不关心编译类型,只关心运行类型)

向下转型:

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

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

  • ②要求转换前父类的引用必须指向的是当前想实现向下转型的子类类型的对象,即有一个向上转型

    • Animal animal = new Cat();  //Cat 是animal,向上转型
      Cat cat =(Cat) animal;  //animal是Cat,向下转型,必须有上一句,才能有这一句
      
  • 当向下转型后,可以调用子类类型中所有的成员

案例:

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


instanceof 比较符:

instanceof :用于判断对象的运行类型是否为XX类型 或者XX类型的子类型

案例:


动态绑定机制:

内容:

  • 当调用对象方法时,该方法会和对象的运行类型(内存地址)绑定
  • 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用

多态的应用---多态数组:

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

多态数组说白了就是数组的类型是父类的引用(编译类型),数组元素是子类运行类型

多态数组的功能就是用一个数组来存放具有同一个父类的不同对象

案例:

先创建Person类,Student类和Teacher类是Person类的子类
3.4 多态-小白菜博客
使用多态数组:

若想调用子类特定的方法通过:instanceof +向下转型来实现


多态的应用----多态参数:

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