Java多态

对象的多态性

  • 以代码为示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Animals {
    public void speak(){
    System.out.println("i am animals");
    }
    }
    public class Cat extends Animals{
    public void speak(){
    System.out.println("i am cat");
    }
    }
    public class Test {
    public static void main(String[] args){
    //一个对象,两种形态
    Animals cat = new Cat();
    cat.speak();
    }
    }
  • 运行后的结果为”i am cat”

  • 猫这类事物既具备猫的形态,又具备动物形态,这就是对象的多样性,简单说,一个对象对应着多种类型
  • 多态在代码中的体现
    • 父类或者接口的引用指向了其子类的对象

多态的好处

  • 提高了代码扩展性,前期定义的代码可以使用后期的内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public abstract class Animals {
    public abstract void eat();
    }
    public class Cat extends Animals{
    public void eat(){
    System.out.println("吃鱼");
    }
    public void catchMouse(){
    System.out.println("抓老鼠");
    }
    }
    public class Dog {
    public void eat(){
    System.out.println("啃骨头");
    }
    public void guardDoor(){
    System.out.println("看门");
    }
    }
    public class Test {

    public static void main(String[] args){
    Cat c1 = new Cat();
    Dog d1 = new Dog();
    Dog d2 = new Dog();
    method(c1);
    method(d1);
    method(d2);
    }
    public static void method(Animals a){
    a.eat();
    }
    }
  • 如上图所示代码,如果很多只猫,很多只狗,为了代码复用性,需要在主类中定义一个方法,可是如果动物种类很多,是否要定义不同参数的许多方法那,答案是不用的,只需要定义个参数为Animals对象的即可

多态的局限性及前提

  • 前期定义的内容,不能调用后期子类定义的特有内容
  • 多态的前提
    • 必须有关系,继承,实现
    • 要有覆盖

多态转型

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //自动类型提升,猫对象提升了动物类型,但特有功能无法访问
    //作用就是限制对猫特有功能的访问
    //专业讲就是 向上转型,将子类型隐藏,就不用使用子类的特有方法
    Animals a = new Cat();
    a.eat();

    //如果还想访问具体动物的特有功能
    //可以进行向下转型
    Cat c = (Cat)a;//向下转型目的:为了使用子类中的特有方法
    c.eat();
    c.catchMouse();

    //错误示例
    Animals a1 = new Dog();
    Cat c1 = (Cat)a1; //ClassCastException类型转换异常
  • 注意:对于转型来说,自始至终都是子类对象在做着类型的变化

类型判断

  • 还是以之前的代码为示例,如果method方法内想进行输出猫,狗的特有功能该怎么做那?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public void method(Animals a){
    a.eat();
    if(a instanceof Cat){
    //instanceof:用于判断对象的具体类型,只能用于引用数据类型判断
    //通常在向下转型前用于健壮性的判断
    Cat c = Cat(a);
    c.catchMouse();
    }else if(a instanceof dog){
    Dog d = Dog(a);
    d.guardDoor();
    }
    }

多态时成员特点

成员变量

  • 编译时:参考引用型变量所属的类中是否有调用的成员变量,有则编译通过,没有则编译失败
  • 运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量
  • 编译和运行都参考左边,如 animals a = new Cat();

成员函数(非静态)

  • 编译时:参考引用型变量所属的类中是否有调用的函数,有则编译通过,没有则编译失败
  • 运行时:参考对象所属的类中是否有调用的函数,
  • 简单说:编译看左边,运行看右边

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Father {
    public void show(){
    System.out.println("i am father");
    }
    }
    public class Son extends Father{
    public void show() {
    System.out.println("i am son");
    }
    }
    public class Test(){
    Father f = new Son();
    f.show();
    }
  • 运行后的结果 i am son

静态函数

  • 编译时:参考引用型变量所属的类中是否有调用的静态方法,有则编译通过,没有则编译失败
  • 运行时:参考对象所属的类中是否有调用的静态方法
  • 简单说:编译和运行都看左边
  • 其实对于静态方法,是不需要对象的,直接类名调用即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Father {
    public static void show(){
    System.out.println("i am father");
    }
    }
    public class Son extends Father{
    public static void show() {
    System.out.println("i am son");
    }
    }
    public class Test(){
    Father f = new Son();
    f.show();
    }
  • 运行结果为 i am father