父类引用指向子类引用。
比如说现在有两个类:Father 类 和 Son 类。
(1)Father f1 = new Son(); //向上转型
(2)Son s1 = (Son)f1; //向下转型
(1)向上转型,f1 引用指向一个 Son 对象。
(2)向下转型,现在的 f1 依然指向 Son 对象。
(1)Father f2 = new Father();
(2)Son s2 = (Son)f2; // 编译无错,运行会出错
(1)f2 指向一个 Father 对象,即父类对象。
(2)s2 指向一个 子类对象 ,子类引用(s2)不能指向父类对象,出错。
总结:
(1)父类引用指向子类对象,而子类引用不能指向父类对象。
(2)向上转型无需强转,向下转型需要强转。
一、向上转型(upcasting):
把子类对象直接赋给父类引用叫向上转型,即将子类转化为父类。
实例:
class Animals{
public void eat(){
System.out.println ("animals eating...");
}
}
class Cow extends Animals{
public void eat(){
System.out.println ("Cow is eating grass! ");
}
public void run(){
System.out.println ("Cow is running!");
}
}
public class Upcasting {
public static void doEat(Animals animals){
animals.eat ();
}
public static void main(String[] args) {
// 父类引用 a 指向 子类对象 Cow
Animals a = new Cow ();
a.eat ();
a.run(); // 报错:此时丢失 run() 方法
Animals a1 = new Animals ();
Cow a2 = new Cow ();
doEat(a1);
doEat (a2);
}
}
在编写代码过程中,编译器出现报错,说明在向上转型过程中,a 虽然指向 子类对象,但已经丢失了 run() 对象。
运行结果:
向上转型的好处:
public static void doEat(Animals animals){
animals.eat ();
}
上述的 doEat() 方法,以父类为参数,在具体的调用中,是以子类为参数调用各自的 eat 方法。在这里利用向上转型,减少了代码量。如果以子类为参数,那岂不是有多少个子类就要些多少个函数吗?
二、向下转型 (downcasting):
把指向子类对象的父类引用赋给子类引用叫向下转型,需要强转。即将父类转化为子类。
实例:
class Transport{
String str = "transport";
public void run(){
System.out.println (str + "is running!");
}
}
class Car extends Transport{
String str = "Car";
public void run(){
System.out.println (str + "is running!");
}
}
public class Downcasting {
public static void main(String[] args) {
Transport t1 = new Car (); //向下转型
Transport t2 = new Transport ();
Car c1 = (Car) t1; //向上转型
Car c2 = (Car) t2; //编译通过,运行出错
}
}
运行时报错,再次说明子类引用不能指向父类对象。
注意:
引用类型 和 指向的对象类型 是两个概念,在调用方法时,主要依据其引用类型。