Java内部泛型类类型参数规则疑问及解析请求
JLS 4.5.2 内部泛型类类型规则详解
规范原文引用
若C的参数化中存在任意通配符类型参数,则:
• C<T1,...,Tn>中字段、方法及构造方法的类型为C<T1,...,Tn>捕获转换后的对应类型(§5.1.10)。
• 设D为C中的(可能泛型的)类或接口声明,则在C<T1,...,Tn>中D的类型为:若D是泛型类,则其所有类型参数均为无界通配符。
规则核心解释
这条规则不是限制你必须把内部泛型类的类型参数声明为无界通配符,而是当外部类使用了带通配符的参数化类型时,编译器默认会将内部泛型类的类型视为“所有类型参数都是无界通配符”的版本。换句话说,如果你通过带通配符的外部类实例直接访问内部泛型类却不指定其类型参数,编译器会自动给内部类的每个类型参数都加上?。
代码示例说明
先定义基础的外部泛型类和内部泛型类:
// 外部泛型类C,类型参数T class C<T> { // 内部泛型类D,类型参数U class D<U> { U value; D(U value) { this.value = value; } U getValue() { return value; } } }
场景1:外部类无通配符(正常使用)
当外部类使用具体类型参数时,内部类可以自由指定类型参数,没有限制:
C<String> c1 = new C<>(); // 直接指定内部类的类型参数为Integer C<String>.D<Integer> d1 = c1.new D<>(123); Integer num = d1.getValue(); // 编译正常,返回Integer类型
场景2:外部类带通配符(触发规则)
当外部类是带通配符的参数化类型时,默认情况下内部类的类型会被处理成全无界通配符版本:
// 外部类使用通配符C<?> C<?> c2 = new C<String>(); // 未指定内部类类型参数时,编译器自动将D视为D<?> C<?>.D<?> d2 = c2.new D<>("hello"); Object obj = d2.getValue(); // 返回类型为Object,因为D<?>的getValue()返回?(上界为Object) // 但你仍可以显式指定内部类的类型参数,只需借助捕获转换(通常用辅助方法实现) public static <T> void processInnerClass(C<T> c) { // 这里可以正常指定内部类的类型参数为String C<T>.D<String> d = c.new D<>("test"); String s = d.getValue(); // 编译正常,返回String类型 } processInnerClass(c2); // 调用时编译器对C<?>执行捕获转换,绑定具体的T类型
规则设计意图
当外部类是带通配符的C<?>时,编译器无法确定外部类类型参数T的具体类型。为了保证类型安全,默认将内部泛型类的所有类型参数设为无界通配符,这样无论外部类的T是什么,内部类的实例都能被安全引用,避免潜在的类型转换错误。
内容的提问来源于stack exchange,提问作者user24723440
相关产品推荐
相关产品推荐

