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

2022-09-02 20:54:48

我收到以下编译消息:

[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

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

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() );
    }
}

答案 1

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

Holder<Class<? extends Exception>> exceptionClassHolder;
exceptionClassHolder =
        new Holder<Class<? extends Exception>>(new Exception().getClass());

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

但是,这与您声明的类型不匹配。它使用嵌套通配符,它不会捕获:虽然是某些特定类型扩展,但嵌套表示字面上的任何类型扩展。Holder<Class<? extends Exception>>CAP#1 extends ExceptionException? extends ExceptionException

虽然 是 的子类型,但不是 的子类型,因为泛型不是协变,所以赋值失败。Class<CAP#1 extends Exception>Class<? extends Exception>Holder<Class<CAP#1 extends Exception>>Holder<Class<? extends Exception>>

通过手动指定 ,可以帮助编译器避免此“陷阱”。Class<? extends Exception>T

在这些帖子上看到我的类似答案:


答案 2
    Holder<? extends Class<? extends Exception>> exceptionClassHolder;
    exceptionClassHolder = new Holder<>( (new Exception()).getClass() );

原因是

  1. 因为你使用的不是异常对象,而是一个异常对象,所以java认为是必需的。Exception.class? extends Exception
  2. 同样适用于 ,再次需要,尽管类是最终的。getClass()? extends Class

当然,总有一天,这将得到简化。


推荐