Java 类泛型的类型不匹配

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/163382/
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-11 09:57:37  来源:igfitidea点击:

Type mismatch for Class Generics

javagenerics

提问by Henry B

I have the following code that won't compile and although there is a way to make it compile I want to understand why it isn't compiling. Can someone enlighten me as to specifically why I get the error message I will post at the end please?

我有以下无法编译的代码,尽管有一种方法可以使其编译,但我想了解为什么它不能编译。有人可以具体说明为什么我会收到我将在最后发布的错误消息吗?

public class Test {
    public static void main(String args[]) {
        Test t = new Test();
        t.testT(null);
    }

    public <T extends Test> void testT(Class<T> type) {
        Class<T> testType = type == null ? Test.class : type; //Error here
        System.out.println(testType);
    }
}

Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>

Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>

By casting Test.classto Class<T>this compiles with an Unchecked castwarning and runs perfectly.

通过转换Test.classClass<T>这个编译Unchecked cast警告并完美运行。

采纳答案by laz

The reason is that Test.class is of the type Class<Test>. You cannot assign a reference of type Class<Test> to a variable of type Class<T> as they are not the same thing. This, however, works:

原因是 Test.class 是 Class<Test> 类型。您不能将 Class<Test> 类型的引用分配给 Class<T> 类型的变量,因为它们不是一回事。然而,这有效:

Class<? extends Test> testType = type == null ? Test.class : type;

The wildcard allows both Class<T> and Class<Test> references to be assigned to testType.

通配符允许将 Class<T> 和 Class<Test> 引用分配给 testType。

There is a ton of information about Java generics behavior at Angelika Langer Java Generics FAQ. I'll provide an example based on some of the information there that uses the Numberclass heirarchy Java's core API.

Angelika Langer Java 泛型常见问题解答中有大量关于 Java 泛型行为的信息。我将根据其中使用Number类层次结构 Java 的核心 API 的一些信息提供一个示例。

Consider the following method:

考虑以下方法:

public <T extends Number> void testNumber(final Class<T> type)

This is to allow for the following statements to be successfully compile:

这是为了能够成功编译以下语句:

testNumber(Integer.class);
testNumber(Number.class);

But the following won't compile:

但以下不会编译:

testNumber(String.class);

Now consider these statements:

现在考虑这些陈述:

Class<Number> numberClass = Number.class;
Class<Integer> integerClass = numberClass;

The second line fails to compile and produces this error Type mismatch: cannot convert from Class<Number> to Class<Integer>. But Integerextends Number, so why does it fail? Look at these next two statements to see why:

第二行无法编译并产生此错误Type mismatch: cannot convert from Class<Number> to Class<Integer>。但是Integerextends Number,为什么会失败呢?看看下面这两个陈述,看看为什么:

Number anumber = new Long(0);
Integer another = anumber;

It is pretty easy to see why the 2nd line doesn't compile here. You can't assign an instance of Numberto a variable of type Integerbecause there is no way to guarantee that the Numberinstance is of a compatible type. In this example the Numberis actually a Long, which certainly can't be assigned to an Integer. In fact, the error is also a type mismatch: Type mismatch: cannot convert from Number to Integer.

很容易看出为什么第 2 行不能在这里编译。您不能将 的实例分配给Number类型的变量,Integer因为无法保证该Number实例的类型兼容。在这个例子中,Number实际上是 a Long,当然不能分配给 a Integer。其实报错也是类型不匹配:Type mismatch: cannot convert from Number to Integer

The rule is that an instance cannot be assigned to a variable that is a subclass of the type of the instance as there is no guarantee that is is compatible.

规则是,不能将实例分配给作为实例类型的子类的变量,因为不能保证兼容。

Generics behave in a similar manner. In the generic method signature, Tis just a placeholder to indicate what the method allows to the compiler. When the compiler encounters testNumber(Integer.class)it essentially replaces Twith Integer.

泛型的行为方式类似。在泛型方法签名中,T只是一个占位符,用于指示该方法允许编译器做什么。当编译器遇到testNumber(Integer.class)它时,它基本上替换TInteger.

Wildcards add additional flexibility, as the following will compile:

通配符增加了额外的灵活性,因为以下将编译:

Class<? extends Number> wildcard = numberClass;

Since Class<? extends Number>indicates any type that is a Numberor a subclass of Numberthis is perfectly legal and potentially useful in many circumstances.

因为Class<? extends Number>指示Number属于Numberthis或它的子类的任何类型都是完全合法的,并且在许多情况下可能有用。

回答by Ken

Remove the conditional and the error is a little nicer...

删除条件和错误更好一点......

public class Test {
    public static void main(String args[]) {
        Test t = new Test();
        t.testT(null);
    }

    public <T extends Test> void testT(Class<T> type) {
    Class<T> testClass = Test.class;
        System.out.println(testClass);
    }
}


Test.java:10: incompatible types
found   : java.lang.Class<Test>
required: java.lang.Class<T>
        Class<T> testClass = Test.class;

回答by erickson

Suppose I extend Test:

假设我扩展测试:

public class SubTest extends Test {
  public static void main(String args[]) {
    Test t = new Test();
    t.testT(new SubTest());
  }
}

Now, when I invoked testT, the type parameter <T>is SubTest, which means the variable testTypeis a Class<SubTest>. Test.classis of type Class<Test>, which is not assignable to a variable of type Class<SubTest>.

现在,当我调用 时testT,类型参数<T>SubTest,这意味着变量testTypeClass<SubTest>Test.class是类型Class<Test>,它不能分配给类型的变量Class<SubTest>

Declaring the variable testTypeas a Class<? extends Test>is the right solution; casting to Class<T>is hiding a real problem.

将变量声明testType为 aClass<? extends Test>是正确的解决方案;投射到Class<T>隐藏了一个真正的问题。