不兼容的类型和新的类型变量
我收到以下编译消息:
[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 extends Exception>
Class extends Exception>
,在哪里?
是通配符捕获 (在编译器错误消息中称为CAP#1
)。 由于您使用带有new Holder<>
的“菱形运算符”,编译器会为T
推断Class
,因此Holder
是创建对象的类型。
但是,这与您声明的Holder
类型不符Holder
Holder
。 它使用嵌套通配符 ,它不捕获:而CAP#1 extends Exception
是一些特定类型扩展Exception
,嵌套? extends Exception
? extends Exception
代表任何扩展Exception
类型 。
而Class
是Class extends Exception>
的子类型Class extends Exception>
Class extends Exception>
, Holder
不是Holder
的子类型Holder
Holder
因为generics不是协变的 ,所以赋值失败。
通过手动指定Class extends Exception>
Class extends Exception>
for T
,你可以帮助编译器避免这个“陷阱”。
在这些post上查看我的类似答案:
- Java:通配符类型不匹配导致编译错误
- 有界通配符相关的编译器错误
Holder extends Class extends Exception>> exceptionClassHolder; exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
原因是
- 因为你没有使用
Exception.class
而是使用Exception对象,java认为? extends Exception
? extends Exception
是必需的。 - 同样适用于
getClass()
? extends Class
虽然Class是final,但是需要? extends Class
。
当然有一天会简化。