向上转型
(1)基本语法:父类类型 引用名称 = new 子类类型()
(2)实质:父类的引用指向了子类对象
为什么要引出向上转型?让我们来看一个例子,定义Dog类和Cat继承Animal类,Fish类和Bone类继承Food类,在Master类中实现喂食功能feed。
传统方法:
public class Master {
public void feed(Dog dog,Bone bone){
System.out.println(dog.getName() + "吃" + bone.getName());
}
public void feed(Cat cat,Fish fish){
System.out.println(cat.getName() + "吃" + fish.getName());
}
public static void main(String[] args) {
Dog dog = new Dog("大黄");
Bone bone = new Bone("大骨头");
Master master = new Master();
master.feed(dog,bone);
Cat cat = new Cat("小花喵");
Fish fish = new Fish("鲤鱼");
master.feed(cat,fish);
}
}
class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Fish extends Food{
public Fish(String name) {
super(name);
}
}
class Bone extends Food{
public Bone(String name) {
super(name);
}
}
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
class Dog extends Animal{
public Dog(String name) {
super(name);
}
}
上述代码中,
public void feed(Dog dog,Bone bone){
System.out.println(dog.getName() + "吃" + bone.getName());
}
public void feed(Cat cat,Fish fish){
System.out.println(cat.getName() + "吃" + fish.getName());
}
若再来一个羊sheep吃草grass,需要继续重载feed()方法,一个可以写,再来十个动物呢?代码复用性不高,由此引入向上转型。将上述feed方法变为
public void feed(Animal animal, Food food){//向上转型,形参为父类,调用时实参为子类
System.out.println(animal.getName() + "吃" + food.getName());
}
可以看出向上转型的优点,还提高了代码的简洁性。
总结
等号左边是编译类型,右边是运行类型。可以调用父类所有的成员(包括属性和方法),不能调用子类的特有成员。
注意:
-
向上转型调用方法时,是看运行类型,从子类的方法向父类寻找调用(即子类有,直接调用;子类无,向父类寻找;父类有且可以调用,返回;否则继续向父类循环);
-
调用属性时,是看编译类型,即调用父类的属性。
为什么不能调用的特有成员,为什么运行时从子类方法向上调用?
因为在编译阶段(javac),是看编译类型,而编译类型没有子类的成员,故不能进行调用。在jvm运行期间(java),是看运行类型,所以从子类的成员方法调用。