# 多态

多态

# 多态用法

// Animal.java
public class Animal {
    public void move() {
        System.out.println("Animal move");
    }
}

// Cat.java
public class Cat extends Animal {
    // 方法覆盖
    public void move() {
        System.out.println("走猫步~");
    }
   public void catchMouse() {
       System.out.println("捉老鼠~");
   }
}

// Bird.java
public class Bird extends Animal{
    public void move() {
        System.out.println("鸟在飞翔~");
    }
    public void sing() {
        System.out.println("在唱歌~");
    }
}

// Test01.java
public class Test01 {
    public static void main(String[] args) {
        // 创建 Animal 对象
        Animal a = new Animal();
        a.move(); // Animal move
        // 创建 Cat 对象
        Cat c = new Cat();
        c.move(); // 走猫步~
        // 创建 Bird 对象
        Bird b = new Bird();
        b.move(); // 鸟在飞翔~
        // -----------------
        // 多态
        // 向上转型
        Animal a1 = new Cat();
        a1.move(); // 走猫步~
        Animal a2 = new Bird();
        a2.move(); // 鸟在飞翔~

        // --------------------------
        Animal a3 = new Cat();
        /**
         * 下面调用 catchMouse() 编译报错
         * 错误: 找不到符号
         * a3.catchMouse();
         *   ^
         * 符号:   方法 catchMouse()
         * 位置: 类型为Animal的变量 a3
         * 原因:在编译的时候,编译器只知道a3变量的数据类型是Animal,也就是说它只会去Animal.class字节码中查找catchMouse()方法,结果没找到,
         * 自然“静态绑定”就失败了,编译没有通过。就像以上描述的错误信息一样:在类型为Animal的变量a中找不到方法catchMouse()。
         */
//        a3.catchMouse();
        // ----------------------------
        /**
         * 向下转型,为了调用子类对象特有的方法
         * 向下转型也就是强制类型转换 将Animal类型转换Cat类型
         */
        Animal a4 = new Cat();
        Cat c1 = (Cat) a4;
        c1.catchMouse(); // 捉老鼠~
        /**
         *  向下转型 编译不报错,运行报错
         *  Exception in thread "main" java.lang.ClassCastException: class Bird cannot be cast to class Cat (Bird and Cat are in unnamed module of loader 'app')
         *         at Test01.main(Test01.java:45)
         *  编译不报错:
         * 因为编译器只知道a5变量是Animal类型,Animal类和Cat类之间存在继承关系,所以可以进行向下转型(前面提到过,只要两种类型之间存在继承关系,
         * 就可以进行向上或向下转型),语法上没有错误,所以编译通过了
         * 运行报错:
         * 报 ClassCastException 错误,翻译为类型转换异常,这种异常通常出现在向下转型的操作过程当中,当类型不兼容的情况下进行转型出现的异常,
         * 之所以出现此异常是因为在程序运行阶段a5 引用指向的对象是一只小鸟,然后我们要将一只小鸟转换成一只猫,这显然是不合理的,因为小鸟和猫之间是没有继承关系的。
         */
        Animal a5 = new Bird();
        // Cat a6 = (Cat) a5; // 编译不报错,运行报错
        // 避免引发上面问题,通过使用 instanceof 运算符
        System.out.println(a5 instanceof Cat); // false
        System.out.println(a5 instanceof Bird); // true
        System.out.println(a5 instanceof Animal); // true

        // 先判断
        if (a5 instanceof Cat) { // false
            Cat c2 = (Cat) a5;
            c2.catchMouse();
        }else if(a5 instanceof Bird){ // true
            Bird b2 = (Bird)a5;
            b2.sing(); // 在唱歌~
        }
    }
}

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

# instanceof 运算符

instanceof 运算符是用来测试一个对象是否为一个类的实例,运算结果是布尔类型,true或者false,假设(c instanceof Cat)结果是true则表示在运行阶段c引用指向的对象是Cat类型, 如果结果是false则表示在运行阶段c引用指向的对象不是Cat类型。在进行任何向下转型的操作之前,要使用instanceof进行判断,这是一个很好的编程习惯

语法格式:
对象 instanceof 类型

// 参考上面完整代码
Animal a5 = new Bird();
// 先判断
if (a5 instanceof Cat) {
    Cat c2 = (Cat) a5;
    c2.catchMouse();
}else if(a5 instanceof Bird){
    Bird b2 = (Bird)a5;
    b2.sing(); // 在唱歌~
}
1
2
3
4
5
6
7
8
9
10

多态存在的三个必要条件:

  • 继承
  • 方法覆盖
  • 父类型引用指向子类型对象

多态显然是离不开方法覆盖机制的,多态就是因为编译阶段绑定父类当中的方法,程序运行阶段自动调用子类对象上的方法,如果子类对象上的方法没有进行重写, 这个时候创建子类对象就没有意义了,自然多态也就没有意义了,只有子类将方法重写之后调用到子类对象上的方法产生不同效果时,多态就形成了。实际上方法覆盖机制 和多态机制是捆绑的,谁也离不开谁,多态离不开方法覆盖,方法覆盖离开了多态也就没有意义了。

静态方法多态

# 多态的作用

多态作用 图片来源地址 (opens new window)