我试图理解 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();
}
}
这导致了一个奇怪的异常,我无法理解:
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)
我尝试做出一些改变。如果我将注释行替换为:
Container<Superclass> b = new Container<Superclass>();
一切正常。这对我来说很有意义。这只是普通的泛型,没有任何通配符。
然后我再次更改为注释行:
Container<?> b = new Container<Superclass>();
令我惊讶的是,这也导致了异常。然而我发现即使使用通配符,Java 也能保证类型安全。我想我明白为什么这会导致异常。
但我就是不明白为什么
Container<? extends Superclass> b = new Container<Superclass>();
结果出现错误。据我所知, 意味着我可以在容器中使用超类的任何子类型。在 Java 中,超类是其自身的子类型,或者至少具有像以前一样的功能。我认为通过使用 extends Superclass 会有类型安全性并且 Java 会接受分配。
我尝试研究我的问题,但找不到任何令人满意的答案。如果有人可以帮助我,我会非常感激,我告诉我,我的错误是什么,并帮助我理解为什么这条线会导致问题。
假设你写的是
Container<? extends Superclass> b = new Container<Subclass>();
// Clearly should compile, that's the whole point of ? extends
b.elem = new Superclass(); // SHOULD NOT compile
第一行之后,
b.elem
具有Subclass
的“真实类型”。您无法将 Superclass
分配给 Subclass
,因此第二行 不应该 已编译。
您已明确告诉 Java 忘记
b
的“真实”类型参数。众所周知,它是 Superclass
的某个子类。但由于它可能是 Subclass
,并且不会让 b.elem = new Superclass()
编译,因此它拒绝编译它。
您只能以有效的方式使用
Container<? extends Superclass>
无论实际使用的是 Superclass
的哪个子类。 b.elem = new Superclass()
则不然。
这是正常现象,也是意料之中的。
您面临的问题与协变的概念以及 Java 通配符泛型与类型声明和赋值相结合时的行为有关。
让我们分解一下您提到的不同案例:
Container<? extends Superclass> b = new Container<Superclass>();
此行声明了一个类型为 b
的变量 Container<? extends Superclass>
,这意味着它可以保存作为 Container
子类型的任何类型的 Superclass
。但是,当您尝试为其分配 Container<Superclass>
时,就会出现问题。编译器正在阻止此分配,因为通配符 ?
代表 Superclass
的未知特定子类型,并且由于 elem
中 Container<? extends Superclass>
的类型未知,因此它不允许您将任何特定对象放入其中(除了null
)。例如,您可以将 Container<Subclass>
分配给 b
,然后 尝试将 Superclass
对象放入其中将不是类型安全的。这就是编译器引发错误的原因。
Container<Superclass> b = new Container<Superclass>();
这很简单并且工作得很好,因为您在 Superclass
的声明和实例化中都使用了确切的类型 Container
。
Container<?> b = new Container<Superclass>();
这一行声明了一个原始类型 b
的变量 Container<?>
,它是 Container<? extends Object>
的简写。这是泛型最宽松的用法,它本质上意味着您可以将任何类型的 Container
(包括 Container<Subclass>
或 Container<SomeOtherClass>
)分配给 b
。但是,由于 elem
中 Container<?>
的类型未知,因此您不能在其中放入任何内容(除了 null
),这就是为什么它在这种情况下通常不太有用。