泛型类构造函数构建带边界泛型类实例的类型推断错误
Java泛型边界下菱形运算符的类型推断失败原因
问题现象
当泛型类的类型参数带有E extends Comparable<? super E>这类自反边界时,使用菱形运算符<>让编译器自动推断类型会失败,而显式指定类型参数则正常。以下是复现代码:
import java.util.Comparator; import java.util.Set; import java.util.TreeSet; public class InferTypeArgApp { static class ACollection<E extends Comparable<? super E>> { // static class ACollection<E> { // <-- 若E无边界,BCollection可正常使用<> private Set<E> mySet; ACollection(Comparator<? super E> comparator) { mySet = new TreeSet<>(comparator); } } static class BCollection<E extends Comparable<? super E>> { private ACollection<E> myACollection; BCollection(Comparator<? super E> comparator) { myACollection = new ACollection<>(comparator); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- 无法推断类型参数 // myACollection = new ACollection<E>(comparator); // <-- 显式指定则正常 } } public static void main(String[] args) { ACollection<Integer> col = new ACollection<>(null); // <-- 此处可正常推断 } }
编译时会抛出如下错误:
$ /usr/local/java/jdk/bin/javac -Xdiags:verbose InferTypeArgApp.java InferTypeArgApp.java:20: error: cannot infer type arguments for ACollection<> myACollection = new ACollection<>(comparator); ^ reason: cannot infer type-variable(s) E#1 (argument mismatch; Comparator<CAP#1> cannot be converted to Comparator<? super E#3>) where E#1,E#2,E#3 are type-variables: E#1 extends Comparable<? super E#1> declared in class ACollection E#2 extends Comparable<? super E#2> declared in class BCollection E#3 extends CAP#1,Comparable<? super E#3> where CAP#1 is a fresh type-variable: CAP#1 extends Object super: E#2 from capture of ? super E#2 1 error
原因解析
- 通配符捕获的影响:BCollection构造方法的参数是
Comparator<? super E>,编译器会对这个通配符进行捕获转换,生成一个新的类型变量CAP#1,它代表? super E的具体类型(即E的某个超类)。 - 类型推断的约束冲突:当编译器尝试推断
ACollection<>的类型参数时,需要同时满足两个条件:- 推断出的类型必须符合
ACollection的泛型边界:E#1 extends Comparable<? super E#1>; - 传入的
Comparator<CAP#1>必须能适配ACollection构造器的参数Comparator<? super E#1>,也就是CAP#1必须是E#1的超类。
- 推断出的类型必须符合
- 边界的不可传递性:虽然
BCollection的E满足E extends Comparable<? super E>,但它的超类CAP#1并不一定满足这个约束。比如假设E是Integer,CAP#1可能是Number,而Number并没有实现Comparable<? super Number>(Integer仅实现了Comparable<Integer>)。编译器无法保证CAP#1符合ACollection的泛型边界,因此无法推导出合法的E#1。 - 显式指定类型的作用:当我们显式写
new ACollection<E>(comparator)时,直接强制类型参数为BCollection的E,而E本身已经满足Comparable<? super E>的边界,同时Comparator<? super E>也正好匹配ACollection构造器的参数要求,因此不会报错。 - 无边界时的推断逻辑:如果
ACollection没有泛型边界,编译器不需要验证类型参数的Comparable约束,只需要匹配参数的兼容性,因此可以成功推断类型。
内容的提问来源于stack exchange,提问作者nhtrnm
相关产品推荐
相关产品推荐

