通俗理解向上转型:就是子类转型成父类。
1. class A
2. {
3.
4. class B extends A
5. {
6. }
7. A a = new B();
这个就是向上转型。
向上转型可以像下面这条语句这么简单:
Shape s = new Circle();
这里,创建一个Circle对象,并把得到的引用立即赋值给s,这样做看似错误(将一种类型赋值给另一种类型),但实际上没有问题,因为通过继承,Circle就是一种Shape(子类是父类,就如男人是人一样)。编译器认可这条语句,也就不会产生错误信息。
假设你调用了一个父类方法(它已经在子类中被覆盖)
s.draw();
你可能认为调用的是Shape的draw()方法,因为这毕竟是一个Shape引用,但此时s真正指向的是Circle对象,由于后期绑定(多态),编译器还是正确调用了Circle的draw()方法。
总结:
1.通过父类型引用指向子类型对象来实现动态调用
B
A a = b;
a.play();
分析:
# 为什么父类型的引用可以指向子类型的对象?
自动实现向上转型。通过A a = b;语句,编译器自动将子类对象向上移动,成为A类型
# a.play()将执行子类还是父类中定义的方法?
子类的。在运行时期,将根据a这个引用所指向的实际对象来获取相应的方法,这也是多态性。一个父类的引用,指向不同的子类对象,执行该方法时,将表现出不同的行为。
2.不能将子类引用指向父类对象
A a = new A();
B b = a;//这样是不行的,对比前面,可以知道父类不是子类(如同人不是男人)
在java中,向上转型是自动进行的,但是向下转型却不是,需要我们强制进行类型转换。如:
B b = new B();
A a = b;
B bb = (B)a;
3.记住一个简单而又复杂的规则,一个类型引用只能引用引用类型自身含有的方法和变量,你可能说这个规则不对,因为父类引用指向子类对象时,最后执行的是子类的方法。其实这并不矛盾,那是因为采用了后期绑定(多态),运行时编译器又根据引用指向的实际类型去调用了子类的方法,而假若子类的这个方法在父类中并没有定义,则编译会出错。
分析:
当你使用父类引用指向子类对象的时候,其实jvm(java virtualmachine)已经使用了编译器产生的类型信息调整转换了。这里你可以这样理解,相当于把不是父类中含有的方法从虚拟函数表中设置为不可见的,注意有可能虚拟函数表中有些函数地址由于在子类中已经被改写了,所以对象虚拟函数表中虚拟函数项目地址已经被设置为子类中完成的方法体的地址了。
总结:
1.向上转换:子类转成父类 如:男人是人;(自动进行)
向下转换:父类转成子类 如:人是男人;(强制类型转换)