知识梳理
1.向上转型的概念:
向上转型又叫自动转型、隐式转型.向上转型就是父类引用指向子类实例,也就是子类的对象可以赋值给父类的对象.
Animal dog = new Dog(); // Dog类是Animal类的子类
注:向上转型是安全的,因为任何子类都继承并接受了父类的方法.从例子中也可以理解,所有的狗都属于狗的父类-动物,这是可行的,但是向下转型则不行,若说所有的动物都是狗就不成立.(所以向下转型要通过强制类型转换,后续章节中会将解)
2.向上转型的应用
1)当一个子类对象向上转型父类类型以后,就被当成了父类对象,所能调用的方法会减少,只能调用子类重写了父类的方法以及父类派生的方法(如set(),get()方法),而不能调用子类特有的方法.
public class Animal{
String name;
int age;
public Animal(){
}
public void eat(){
System.out.println("animal吃东西");
}
public static void die(){
System.out.println("animal死亡");
}
}
public class Dog extends Animal{
String favoriteFood;
public void eat(){
System.out.println("吃肉");
}
public void run(){
System.out.println("夕阳下奔跑的小狗");
}
public static void die(){
System.out.println("dog死亡");
}
}
public static void main(String[] args){
Animal animal = new Dog();
animal.age = 2;
animal.name = "小强";
animal.favoriteFood = "骨头"; // 访问子类的属性报错
animal.eat(); // 调用的是子类的方法,输出结果是"吃肉"
animal.run();// 访问子类特有的方法报错
animal.die();// 调用的是父类的方法,输出结果是"animal死亡"
}
2)父类中的静态方法时不允许被子类重写的
如父类的有静态方法die()
当子类Dog中也定义同名方法时,此时die()算dog类自己独有的方法:
Animal animal = new Dog(); // 向上转型
animal.die();// 调用的是Animal类的die()方法,而不是调用Dog的die()方法
// 输出结果是:animal死亡
知识扩展
多态的实现可以通过向上转型和动态绑定机制来完成,向上转型实现了将子类对象向上转型为父类类型,而动态绑定机制能识别出对象转型前的类型,从而自动调用该类的方法,两者相辅相成.
动态绑定:
绑定就是讲一个方法调用同一个方法所在的类连接到一起就是绑定.绑定分为静态绑定和动态绑定两种.
- 静态绑定:在程序运行之前进行绑定(由编译器和链接程序完成的),也叫做前期绑定.
- 动态绑定:在程序运行期间由JVM根据对象的类型自动判断应该调用哪个方法,也叫做后期绑定.
静态绑定的例子:
如有一类Human,它派生出来三个子类Chines类,American类和British类,三个子类中都重写了父类中的方法speak():void,在测试类中用静态绑定的方式调用方法speak().
Chinese c = new Chinese();
c.speak();
American a = new American();
a.speak();
British b = new British();
b.speak();
这种调用方式是在代码里指定的,编译时编译器就知道c调用的是Chinese的speak(),a调用的是American的speak().
动态绑定的例子:
如果我们在测试类中做以下改动:
// 生成父类对象数组,数组长度为5
Human[] human = new Human[5];
int n;
for(int i = 0; i < human.length;i++){
n = (int)(Math.random() * 3); // 随机产生从0到2中的一个数
switch(n){
case 0: human[i] = new Chinese();break;
case 1: human[i] = new American();break;
case 2: human[i] = new British();break;
}
}
// 循环输出,循环体中每个对象分别调用speak()方法
for(int i = 0;i < human.length;i ++){
human[i].speak();
}
此时,Human类中随机生成Chinese类,American类和British类的对象,编译器不能根据代码直接确定调用那个类中的speak()方法,知道运行时才能根据产生的随机数n的值来确定human[i]到底代表哪一个子类的对象,这样才能最终确定调用的是那个类的speak()方法,这就是动态绑定.
网友评论