父类数据类型与子类数据类型的差异及变量类型影响探究
Java父类引用指向子类对象 vs 子类引用指向子类对象的差异
这两种写法创建的实际对象都是MySubThing实例,但引用的类型不同,会直接影响后续代码能调用的成员、多态的使用场景,具体差异如下:
1. 可访问的成员范围不同
- 用
MyThing myThing = new MySubThing();时,编译器只把myThing当作MyThing类型处理,你只能调用MyThing中定义的方法/属性(包括父类继承来的,但不包括MySubThing新增的)。哪怕MySubThing重写了MyThing的方法,执行时会走子类的实现,但子类独有的方法或属性直接调用会编译报错。
比如如果MySubThing有个void doSubStuff()方法,用MyThing类型的myThing直接调用myThing.doSubStuff()会编译失败,必须先强制转成MySubThing类型才能调用。 - 用
MySubThing myThing = new MySubThing();时,myThing是子类类型,能直接调用MyThing的所有非私有成员,加上MySubThing自己新增的成员,不需要任何转换。
2. 多态场景的适配性不同
第一种写法是Java多态的典型应用,适合需要统一处理多个子类实例的场景:
List<MyThing> thingList = new ArrayList<>(); thingList.add(new MySubThing()); thingList.add(new MyOtherSubThing()); // 另一个MyThing的子类 for (MyThing thing : thingList) { thing.commonMethod(); // 遍历执行各自子类的commonMethod实现 }
这种情况下,不管集合里放的是哪个子类的实例,都能通过父类引用统一调用方法,实际执行的是子类的重写逻辑。
而第二种写法的引用是具体子类类型,没法直接放到父类类型的集合里当然可以手动向上转型,但那样就回到第一种情况了,没法直接利用多态的统一处理能力。
3. 类型转换的要求不同
- 第一种写法如果要调用子类独有的成员,必须做向下转型,而且建议先判断类型避免ClassCastException:
if (myThing instanceof MySubThing) { ((MySubThing) myThing).doSubStuff(); }
- 第二种写法本身就是子类类型,不需要转型就能调用所有子类成员;如果要转成父类类型是向上转型,这是安全且自动完成的,比如
MyThing parentRef = myThing;不会有任何问题。
为什么你觉得“结果一致”?
如果你的MySubThing只重写了MyThing的方法,没有新增任何独有的成员,那两种写法调用重写方法时,执行的都是子类的实现,表面结果确实一样,但本质上第一种写法的引用被限制了父类的接口,后续如果要扩展子类功能,第一种写法需要转型才能使用,第二种则直接可用。
内容的提问来源于stack exchange,提问作者rado_rud
相关产品推荐
相关产品推荐

