Java 多态性和列表

bam*_*o10 2 java polymorphism extends list

假设我有以下类结构

public abstract class MyClass{}

public class MyClassA extends MyClass{}

public class MyClassB extends MyClass{}
Run Code Online (Sandbox Code Playgroud)

如何创建包含 MyClassA 和 MyClassB 元素且没有异议的 MyClass 元素列表?

例如

    List<MyClass> myList = new LinkedList<MyClassA>();
Run Code Online (Sandbox Code Playgroud)

Kal*_*lja 6

根据您的需求,您有多种选择。您可以使用普通List<MyClass>类型对象。这允许您添加类型MyClassA和的对象MyClassB。不能将 List 类型对象设置为类型为 的变量List<MyClass>。这是由于一个称为方差的概念。大多数支持泛型(参数化多态性)的编程语言中存在三种类型的方差。

不变性

不变性不允许一个人在任一方向上偏离某种类型。默认情况下,Java 中的泛型就是这种情况,这就是为什么您不能将 a 分配List<MyClassA>给 的变量List<MyClass>。想象一下以下场景:

List<MyClassA> listA = new List<MyClassA>();
List<MyClass> list = (List<MyClass>) listA; // Produces a compilation error...
list.add(new MyClassB()); // ... because this would be a big no-no
Run Code Online (Sandbox Code Playgroud)

协方差

协方差允许您使用指定的参数类型或其任何子类型。在 Java 中,您可以使用 extends 关键字来指定协方差:List<? extends MyClass>。允许将 List 类型对象分配给此类变量。但是,使用协变,如果没有显式强制转换,则无法将任何对象添加到通用对象实例中。也就是说你不能执行以下操作:

List<? extends MyClass> list = new LinkedList<MyClassA>();
list.add(new MyClassA());
Run Code Online (Sandbox Code Playgroud)

这是合乎逻辑的。毕竟,您无法确切知道您正在处理的列表类型。它也可能是一个List<MyClassB>.

逆变

逆变与协变相反,使用 super 关键字指定:List<? super MyClassA>。允许将List<MyClass>(但不是List<MyClassB>)类型对象分配给此类变量。通过逆变,您可以添加指定类型参数的任何子类型(类型层次结构中的下限)。也就是说,允许执行以下操作:

List<? super MyClass> list = new LinkedList<MyClass>();
list.add(new ChildA());
Run Code Online (Sandbox Code Playgroud)

但是,您无法确切知道该对象是什么类型的 List。也就是说,您只能直接将存储在列表中的对象分配给 Object 类型的变量,而无需显式强制转换:

Object o = list.get(0);
if (o instanceof MyClassA) {
  MyClassA mca = (MyClassA) o;
  //...
}
Run Code Online (Sandbox Code Playgroud)

我希望这有助于澄清一些事情。