说我有以下类结构
public abstract class MyClass{}
public class MyClassA extends MyClass{}
public class MyClassB extends MyClass{}
如何在没有异议的情况下创建包含MyClassA和MyClassB元素的MyClass元素列表?
e.g。
List<MyClass> myList = new LinkedList<MyClassA>();
答案 0 :(得分:3)
多态性是一种物体采取多种形式的能力。当父类引用用于引用子类对象时,OOP中最常见的多态性使用发生。父类引用可以保存其任何子类的对象。因此父类的集合可以保存子类对象。例如:
List<MyClass> myClassList = new ArrayList<MyClass>();
答案 1 :(得分:1)
您可以使用List<? extends MyClass> myList = new ArrayList<MyClassA>();
之类的通配符,但这样只会让您从列表中获取项目。添加项目并不安全,因为您无法知道List
的基础类型是什么。您必须直接将项目添加到列表的实际实例中,如:
List<? extends MyClass> myList = null;
ArrayList<MyClassA> actualListA = new ArrayList<MyClassA>();
myList = actualListA;
MyClassA myClassA = new MyClassA();
actualListA.add(myClassA);
myList.add(new MyClassA()); //Nope, you can't do this because myList could be assigned to an array of MyClassB items like the following.
//Reassign
ArrayList<MyClassB> actualListB = new ArrayList<MyClassB>();
myList = actualListB;
MyClassB myClassB = new MyClassB();
actualListB.add(myClassB);
//Get item
MyClass item = myList.get(0);// This will give you the myClassB object.
答案 2 :(得分:1)
根据您的需要,您有多种选择。您可以使用普通的List<MyClass>
类型对象。这允许您添加MyClassA
和MyClassB
类型的对象。您不能将List类型对象设置为类型为List<MyClass>
的变量。这是由于一个名为 variance 的概念。在支持泛型的大多数编程语言中存在三种类型的方差(参数化多态)。
Invariance 不允许任何一个方向偏离类型。默认情况下,Java中的泛型就是这种情况,这就是为什么你不能将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
协方差允许您使用指定的参数类型或其任何子类型。在Java中,您使用extends关键字来指定协方差:List<? extends MyClass>
。允许将List类型对象分配给这样的变量。但是,使用协方差,如果没有显式强制转换,则无法将任何对象添加到通用对象实例中。那就是你不能做到以下几点:
List<? extends MyClass> list = new LinkedList<MyClassA>();
list.add(new MyClassA());
这是合乎逻辑的。毕竟,您无法准确知道您正在处理的List的类型。它也可能是List<MyClassB>
。
逆变量与协方差相反,并使用超级关键字List<? super MyClassA>
指定。允许将List<MyClass>
(但不是List<MyClassB>
)类型对象分配给这样的变量。使用逆变,您可以添加指定类型参数的任何子类型(类型层次结构中的下限)。也就是说,允许执行以下操作:
List<? super MyClass> list = new LinkedList<MyClass>();
list.add(new ChildA());
但是,您无法确切知道对象的List类型。也就是说,你只能直接将存储在列表中的对象分配给Object类型的变量,而不需要显式转换:
Object o = list.get(0);
if (o instanceof MyClassA) {
MyClassA mca = (MyClassA) o;
//...
}
我希望这有助于澄清一些事情。
答案 3 :(得分:0)
使用List
接口实现具体/抽象类。这样的事情。
List<MyClass> list = new ArrayList<MyClass>();