前言
我们前面认识了向上转型的概念。即父类引用指向子类对象,如果一个父类有若干个子类,那么编译器是如何知道这个父类引用具体指向的是哪一个子类对象呢?
一、绑定的概念
绑定:将一个方法调用与一个方法主体关联起来叫做绑定。
-
前期绑定:在程序执行前进行绑定(如果有的话,由编译器和连接程序实现)。此方式为面向过程语言中默认的绑定方式。前言中提出的疑惑主要是因为前期绑定的概念影响。因为当编译器只有一个父类引用时,编译器无法知道究竟调用哪一个方法才对。
-
后期绑定:也称做动态绑定或运行时绑定 ,在运行时根据对象的类型进行绑定(在运行时根据实际的对象类型调用相应的方法)。该方法解决了前期绑定产生的疑惑,即解决了前言中的问题。
实际上动态绑定(后期绑定)就是多态。
二、多态
在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。多态不但能够改善代码的组织结构和可读性,还大大加强了程序的可扩展性。
具体概念:在运行时能够判断对象的类型从而调用相对应的方法。
public class Test {
public static void main (String [] args) {
Cat c = new Cat("catname","blue");
Dog d = new Dog("dogname","black");
Kid k1 = new Kid ("xiaohua",c);
Kid k2 = new Kid ("xiaohong",d);
k1.myPetEnjoy();
k2.myPetEnjoy();
}
}
class Kid {
private String name;
private Animal pet;
Kid (String name, Animal pet) {
this.name = name;
this.pet = pet;
}
public void myPetEnjoy () {
pet.enjoy();
}
}
class Animal {
public String name;
Animal (String name){
this.name = name;
}
public void enjoy () {
System.out.println("Animal ......");
}
}
class Cat extends Animal {
public String eyeColor;
Cat (String name,String eyeColor) {
super(name);
this.eyeColor = eyeColor;
}
public void enjoy () {
System.out.println("Cat .....");
}
}
class Dog extends Animal {
public String furColor;
Dog (String name,String furColor) {
super(name);
this.furColor = furColor;
}
public void enjoy () {
System.out.println("Dog......");
}
}
/*class Bird extends Animal {
public String furColor;
Bird (String name,String furColor) {
super(name);
this.furColor = furColor;
}
public void enjoy () {
System.out.println("Bird......");
}
}*/
运行结果
Cat .....
Dog......
例子中的一部分代码
Kid k1 = new Kid (“xiaohua”,c);
…
Kid (String name, Animal pet)
…
// 小孩k1名字叫xiaohua 养了一只猫c(叫做catname,eyeColor为blue),c当做Animal传递的,只能访问Animal中的方法。但由于有多态机制的存在,
在执行的过程中判断出来为Cat的对象,所以最终调用的是Cat中的方法,输出“Cat …”
可扩展性:前面说了,多态大大加强了程序的可扩展性。比如,在上诉程序的基础上,又多增加一种动物鸟,则只需编写该鸟相关的代码,不需要改变其余的方法。(当然main方法改变是正常的)
三、多态存在的必要条件
1. 要有继承
2. 要有方法重写
3. 父类引用指向子类对象。(向上转型)
需要清楚
我们知道父类对象的引用是没有办法访问子类里面新添加的属性(成员变量和方法)。因为子类对象把自己看做是父类的类型。
所以要知道,在多态机制下,我们访问的成员变量是父类的,访问的方法是子类的重写方法。