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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:40:19  来源:igfitidea点击:

incompatible types and fresh type-variable

javagenerics

提问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#1indeed 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 Tand 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 Exceptionis some specific typeextending Exception, the nested ? extends Exceptionrepresents 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

原因是

  1. Because you are not using Exception.classbut an Exception object, java thinks ? extends Exceptionis required.
  2. The same holds for getClass(), again ? extends Classneeded, though Class is final.
  1. 因为您使用的不是Exception.classException 对象,所以 java 认为? extends Exception是必需的。
  2. 这同样适用于getClass(),再次? extends Class需要,尽管 Class 是最终的。

Certainly one day this will be simplified.

当然有一天这会被简化。