Java 不兼容的类型和新的类型变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20543966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
incompatible types and fresh type-variable
提问by Marcus Junius Brutus
I get the following compilation message:
我收到以下编译消息:
[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
It would seem to me that the according to the message all should be correct. CAP#1
indeed extends Exception. So how should the above message be understood? SSCCE below (initially not posted since I was hoping to understand the error message itself in the general case):
在我看来,根据消息,一切都应该是正确的。CAP#1
确实扩展了异常。那么应该如何理解上面的消息呢?下面的 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() );
}
}
采纳答案by Paul Bellora
Unfortunately, the existing answers don't explain what's going on here. First, the solution is to simply specify the type argument to Holder
:
不幸的是,现有的答案并没有解释这里发生了什么。首先,解决方案是简单地将类型参数指定为Holder
:
Holder<Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder =
new Holder<Class<? extends Exception>>(new Exception().getClass());
The reason your version didn't work is because new Exception().getClass()
returns a Class<? extends Exception>
, where ?
is a wildcard capture(referred to in the compiler error message as CAP#1
). Since you use the "diamond operator" with new Holder<>
, the compiler infers Class<CAP#1 extends Exception>
for T
and so Holder<Class<CAP#1 extends Exception>>
is the type of the created object.
您的版本不起作用的原因是new Exception().getClass()
返回 a Class<? extends Exception>
,其中?
是通配符捕获(在编译器错误消息中称为CAP#1
)。由于您使用的“钻石经营者”用new Holder<>
,编译器推断Class<CAP#1 extends Exception>
的T
,因此 Holder<Class<CAP#1 extends Exception>>
是创建的对象的类型。
However, this doesn't match your declared type of Holder<Class<? extends Exception>>
. It uses a nested wildcard, which doesn't capture: while CAP#1 extends Exception
is some specific typeextending Exception
, the nested ? extends Exception
represents literally any typeextending Exception
.
但是,这与您声明的Holder<Class<? extends Exception>>
. 它使用嵌套通配符,它不捕获:虽然CAP#1 extends Exception
是某种特定类型的扩展Exception
,但嵌套? extends Exception
实际上表示任何类型的扩展Exception
。
And while Class<CAP#1 extends Exception>
is a subtype of Class<? extends Exception>
, Holder<Class<CAP#1 extends Exception>>
is not a subtype of Holder<Class<? extends Exception>>
because generics aren't covariant, so the assignment fails.
而 whileClass<CAP#1 extends Exception>
是 的子类型Class<? extends Exception>
,Holder<Class<CAP#1 extends Exception>>
不是 的子类型,Holder<Class<? extends Exception>>
因为泛型不是协变的,所以赋值失败。
By manually specifying Class<? extends Exception>
for T
, you help the compiler avoid this "trap".
通过手动指定Class<? extends Exception>
for T
,您可以帮助编译器避免这个“陷阱”。
See my similar answers on these posts:
请参阅我在这些帖子上的类似答案:
回答by Joop Eggen
Holder<? extends Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder = new Holder<>( (new Exception()).getClass() );
The reason is that
原因是
- Because you are not using
Exception.class
but an Exception object, java thinks? extends Exception
is required. - The same holds for
getClass()
, again? extends Class
needed, though Class is final.
- 因为您使用的不是
Exception.class
Exception 对象,所以 java 认为? extends Exception
是必需的。 - 这同样适用于
getClass()
,再次? extends Class
需要,尽管 Class 是最终的。
Certainly one day this will be simplified.
当然有一天这会被简化。