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)
根据您的需求,您有多种选择。您可以使用普通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)
我希望这有助于澄清一些事情。