一、什么是多态(方法的多态)
- 多态是同一个行为具有多个不同表现形式或形态的能力。
- 多态就是同一个接口,使用不同的实例而执行不同操作。
比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:
酒 a = 剑南春
酒 b = 五粮液
酒 c = 酒鬼酒
…
这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
-
多态的优缺点
优点:
- 提高了代码的维护性(继承保证)
- 提高了代码的扩展性(多态保证)
缺点:
- 不能使用子类的特有功能
二、多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象(引用还是指向父类)(向上转型)
比如:
Parent p = new Child();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
三、例子
1 class Animal{ 2 public int month = 2; 3 public void eat(){ 4 System.out.println("动物吃东西"); 5 } 6 7 } 8 9 class Dog extends Animal{ 10 public int month = 3; 11 12 public void eat() { 13 System.out.println("小狗吃肉"); 14 } 15 16 public void sleep() { 17 System.out.println("小狗睡午觉"); 18 } 19 } 20 21 class Cat extends Animal{ 22 public int month = 4; 23 24 public void eat() { 25 System.out.println("小猫吃鱼"); 26 } 27 } 28 29 public class Test { 30 public static void main(String[] args){ 31 Animal a = new Dog(); 32 Animal b = new Cat(); 33 a.eat(); 34 System.out.println(a.month); 35 //下面代码编译时会出错 36 // a.sleep(); 37 b.eat(); 38 System.out.println(b.month); 39 40 } 41 }
a对象编译时类型是Animal,运行时类型是Dog;
b对象编译时类型是Animal,运行时类型是Cat。
当运行时调用引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就表现出:相同类型的变量调用同一个方法时表现出不同的行为特征,这就是多态。
该例中:当他们调用eat方法时,实际调用的是父类Animal中被覆盖的eat方法。
运行结果:
上例中main方法中注释了a.sleep(),由于a的编译时类型为Animal,而Animal类中没有sleep方法,因此无法在编译时调用sleep方法。
对象的实例变量不具备多态性
上例中a,b对象分别调用了month,可以看到,其输出结果都是2
四、总结
多态成员访问的特点
Parent p = new Child();
成员变量
编译看左边(父类),运行看左边(父类);无论如何都是访问父类的成员变量。
成员方法
编译看左边(父类),运行看右边(子类),动态绑定。
Static方法
编译看左边(父类),运行看左边(父类)。
只有非静态的成员方法,编译看左边,运行看右边。
这样,我们也可以得出多态的局限:
不能使用子类特有的成员属性和子类特有的成员方法。