使用通配符时 Java 泛型类型不匹配

Jan*_*Jan 2 java oop generics wildcard subtyping

我试图理解 Java 中的泛型,但遇到了一些问题。这是我写的代码:

class Superclass{
}

class Subclass extends Superclass{
}

class Container <T>{
    T elem;
}

public class Test {
    public static void main(String[] args) {
        Container<? extends Superclass> b = new Container<Superclass>();
        b.elem = new Superclass();
    }   
}
Run Code Online (Sandbox Code Playgroud)

这个结果是一个奇怪的异常,我无法理解:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Type mismatch: cannot convert from Superclass to capture#1-of ?

    at Test.main(Test.java:4)
Run Code Online (Sandbox Code Playgroud)

我尝试做出一些改变。如果我将注释行替换为:

Container<Superclass> b = new Container<Superclass>();
Run Code Online (Sandbox Code Playgroud)

一切正常。这对我来说很有意义。这只是普通的泛型,没有任何通配符。

然后我再次更改为注释行:

Container<?> b = new Container<Superclass>();
Run Code Online (Sandbox Code Playgroud)

我很惊讶这也导致了异常。然而我发现即使使用通配符,Java 也能保证类型安全。我想我明白为什么这会导致异常。

但我就是不明白为什么

Container<? extends Superclass> b = new Container<Superclass>();  
Run Code Online (Sandbox Code Playgroud)

结果我出错了。据我所知,<? extends Superclass> 意味着我可以在容器中使用超类的任何子类型。在 Java 中,超类是其自身的子类型,或者至少具有像以前一样的功能。我认为通过使用 extends Superclass 会有类型安全并且 Java 会接受分配。

我尝试研究我的问题,但找不到任何令人满意的答案。如果有人可以帮助我,告诉我,我的错误是什么,并帮助我理解为什么这条线会导致问题,我将非常感激。

Lou*_*man 5

假设你写的是

Container<? extends Superclass> b = new Container<Subclass>(); 
  // Clearly should compile, that's the whole point of ? extends

b.elem = new Superclass(); // SHOULD NOT compile
Run Code Online (Sandbox Code Playgroud)

第一行之后,b.elem有“真实类型” Subclass。您不能将 a 分配Superclass给 a Subclass,因此第二行不应编译。

您已明确告诉 Java 忘记 的“真实”类型参数b。众所周知,它是 的某个子类Superclass。但由于它可能是Subclass,并且不允许b.elem = new Superclass()编译,因此它拒绝编译它。

您只能以无论实际使用Container<? extends Superclass>哪个子类都有效的方式使用 a 。才不是。Superclass b.elem = new Superclass()

这是正常现象,也是意料之中的。