Java通配符参数困惑:为何父类类型变量可调用子类方法?
问题解答
先贴出你的代码方便讨论:
public class A { void meth1() {} } public class B extends A { void meth2() {} } public class generic_class<T extends A> { T var1; public void meth4(generic_class<? extends B> gc) { gc.var1.meth2(); } }
你困惑的点在于:泛型擦除后var1的类型应该是上限A,为什么能调用B独有的meth2()?
核心要区分编译期检查和运行时擦除两个阶段:
编译期:编译器靠通配符约束做类型校验
你声明的generic_class<? extends B>告诉编译器:这个gc的类型参数必然是B或者B的子类。所以编译器会把gc.var1的编译期类型判定为B(通配符? extends B的上限),而非A。既然编译器确定var1肯定是B或其子类的实例,自然允许调用B中定义的meth2()。运行时:泛型擦除后靠动态绑定执行正确方法
运行时泛型信息确实会被擦除,var1的静态类型会变成A,但此时调用方法是基于实际对象的运行时类型的动态绑定。因为var1实际指向的是B或其子类的对象,JVM会找到对应对象的meth2()方法执行,不会出现找不到方法的问题。
总结来说,编译期的通配符约束保证了代码的合法性,运行时的动态绑定保证了方法能正确执行,泛型擦除并没有打破这个逻辑。
内容的提问来源于stack exchange,提问作者Rudra Shivgan
相关产品推荐
相关产品推荐

