Java泛型使用通配符时出现类型不匹配问题求助
你对<? extends Superclass>的理解存在关键误区:这个通配符的作用不是让容器“容纳Superclass的任何子类(含自身)”,而是限制容器的类型参数是Superclass的某个子类(含自身),但编译器无法确定具体是哪一个——正是这种不确定性导致了编译错误。
为什么赋值会失败?
当你声明Container<? extends Superclass> b时,编译器只知道b引用的容器,其类型参数是Superclass的子类(包括Superclass本身),但它无法确定具体是哪一种类型:它可能是Container<Superclass>,也可能是Container<Subclass>,甚至是其他未知的Superclass子类容器。
如果允许你执行b.elem = new Superclass(),就会出现潜在的类型安全问题:假设b实际指向的是Container<Subclass>实例,那把Superclass对象赋值给Subclass类型的elem,相当于把父类对象存入子类专属容器,这完全违反了泛型的类型约束。编译器为了杜绝这种风险,直接禁止了对<? extends T>类型的容器进行除null之外的写入操作。
正确的使用场景
<? extends Superclass>适合用于读取操作:你可以安全地把b.elem赋值给Superclass类型的变量,因为不管实际类型是什么,它肯定是Superclass的子类,向上转型是安全的,比如:
Container<? extends Superclass> b = new Container<Subclass>(); Superclass obj = b.elem; // 编译通过
而当你需要写入操作时,应该使用确定的类型(比如Container<Superclass>),或者使用下界通配符<? super T>(如果需要存入子类对象到父类容器的场景)。
对比你的测试情况
- 当用
Container<Superclass> b时,编译器明确知道elem的类型是Superclass,所以可以安全赋值任何Superclass或其子类对象,完全符合泛型的类型安全规则。 - 当用
Container<?> b时,这是无界通配符,编译器同样无法确定具体类型,因此写入操作也被禁止,原理和上界通配符一致。
内容的提问来源于stack exchange,提问作者Jan

