首先感谢这位大神的博客,我在其代码下加个人理解,有可能不正确,希望看出来的可以指出,加以改正
A类:package a.b;public class A {void aMthod() { System.out.println("A method");}}A的子类B:package a.b;public class B extends A {void bMethod1() { System.out.println("B method 1");}void bMethod2() { System.out.println("B method 2");}}C类:package a.b;public class C { public static void main(String[] args) { A a1 = new B(); // 向上转型 a1.aMthod(); // 调用父类aMthod(),a1遗失B类方法bMethod1()、bMethod2() B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误 b1.aMthod(); // 调用父类A方法 b1.bMethod1(); // 调用B类方法 b1.bMethod2(); // 调用B类方法 A a2 = new A(); B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错 b2.aMthod(); b2.bMethod1(); b2.bMethod2(); }}
个人理解
为什么第一个向下转型成功? 因为
A a1 = new B(); // 向上转型,这个a1对象其实指向的是子类B的一个对象//举例:鸟 = new 八哥//有时为了代码简洁,操作时我不关注它是八哥,所以向上转型会遗失八哥独有的方法,比如嗑瓜子/*上面用法多见于传参,你传的是鸟就行,然后执行传进来的方法,这里举例为执行叫你传八哥,就执行八哥的模仿人说话,你传啄木鸟就执行啄木鸟的叽叽喳喳,此时,你就不能执行八哥的嗑瓜子方法,因为有可能传其他的品种的鸟,因此会向上转型遗失独有的方法*//*但是有时我又想使用八哥独有的嗑瓜子方法,这时候,a1对象(其实指向B的一个对象实例,在此,a1本来就指向一个B类的实例(八哥),只是强调返回的八哥是一只鸟),所以向上转型为八哥,当然没问题*/B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误
为什么第二个向下转型不安全? 因为
A a2 = new A();//沿用鸟和八哥的例子,这里毫无疑问new出来的a2是一只鸟,具体是什么鸟,不知道 B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错/*因为a2是鸟类(父类)的一个实例对象,不确定是什么品种,这时候你将a2向下转为八哥,肯定是不行的,因为自然界里鸟有可能是一只啄木鸟,你将有可能是啄木鸟的鸟转换为八哥,肯定是不行的*/