我收到以下编译信息:
[javac] ... error: incompatible types
[javac] exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
[javac] ^
[javac] required: Holder<Class<? extends Exception>>
[javac] found: Holder<Class<CAP#1>>
[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<T> {
public T t;
public Holder(T t) {
this.t = t;
}
}
public class FooMain {
public static void main(String args[]) throws Exception {
Holder<Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
}
}
答案 0 :(得分:23)
不幸的是,现有的答案并没有解释这里发生了什么。首先,解决方案是简单地指定Holder
的类型参数:
Holder<Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder =
new Holder<Class<? extends Exception>>(new Exception().getClass());
您的版本无效的原因是new Exception().getClass()
返回Class<? extends Exception>
,其中?
是wildcard capture(在编译器错误消息中称为{{ 1}})。由于您将“菱形运算符”与CAP#1
一起使用,编译器会为new Holder<>
推断Class<CAP#1 extends Exception>
,因此T
是所创建对象的类型。
但是,这与您声明的Holder<Class<CAP#1 extends Exception>>
类型不符。它使用nested wildcard,但不会捕获:Holder<Class<? extends Exception>>
某些特定类型延伸CAP#1 extends Exception
,嵌套Exception
代表字面任何类型扩展? extends Exception
。
虽然Exception
是Class<CAP#1 extends Exception>
的子类型,但Class<? extends Exception>
不是Holder<Class<CAP#1 extends Exception>>
的子类型,因为generics aren't covariant,因此分配失败。
通过为Holder<Class<? extends Exception>>
手动指定Class<? extends Exception>
,可以帮助编译器避免使用此“陷阱”。
在这些帖子上查看我的类似答案:
答案 1 :(得分:2)
Holder<? extends Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
原因是
Exception.class
而是使用Exception对象,所以java认为? extends Exception
是必需的。getClass()
,同样需要? extends Class
,尽管Class是final。 当然有一天会简化。