不兼容的类型和新的类型变量

我收到以下编译消息:

[javac] ... error: incompatible types [javac] exceptionClassHolder = new Holder( (new Exception()).getClass() ); [javac] ^ [javac] required: Holder<Class> [javac] found: Holder<Class> [javac] where CAP#1 is a fresh type-variable: [javac] CAP#1 extends Exception from capture of ? extends Exception [javac] 1 error 

在我看来,根据信息所有应该是正确的。 CAP#1确实扩展了Exception。 那么如何理解上述信息呢? 下面的SSCCE(最初没有发布,因为我希望在一般情况下理解错误消息本身):

 class Holder { public T t; public Holder(T t) { this.t = t; } } public class FooMain { public static void main(String args[]) throws Exception { Holder<Class> exceptionClassHolder; exceptionClassHolder = new Holder( (new Exception()).getClass() ); } } 

不幸的是,现有的答案并没有解释这里发生了什么。 首先,解决方案是简单地为Holder指定类型参数:

 Holder> exceptionClassHolder; exceptionClassHolder = new Holder>(new Exception().getClass()); 

你的版本不起作用的原因是因为new Exception().getClass()返回一个Class Class ,在哪里?通配符捕获 (在编译器错误消息中称为CAP#1 )。 由于您使用带有new Holder<>的“菱形运算符”,编译器会为T推断Class ,因此Holder>是创建对象的类型。

但是,这与您声明的Holder>类型不符Holder> Holder> 。 它使用嵌套通配符 ,它不捕获:而CAP#1 extends Exception一些特定类型扩展Exception ,嵌套? extends Exception ? extends Exception代表任何扩展Exception 类型

ClassClass的子类型Class ClassHolder>不是Holder>的子类型Holder> Holder>因为generics不是协变的 ,所以赋值失败。

通过手动指定Class Class for T ,你可以帮助编译器避免这个“陷阱”。

在这些post上查看我的类似答案:

  • Java:通配符类型不匹配导致编译错误
  • 有界通配符相关的编译器错误
  Holder> exceptionClassHolder; exceptionClassHolder = new Holder<>( (new Exception()).getClass() ); 

原因是

  1. 因为你没有使用Exception.class而是使用Exception对象,java认为? extends Exception ? extends Exception是必需的。
  2. 同样适用于getClass() ? extends Class 虽然Class是final,但是需要? extends Class

当然有一天会简化。