Java多态性和列表

时间:2014-01-14 16:31:20

标签: java list polymorphism extends

说我有以下类结构

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>();

4 个答案:

答案 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>类型对象。这允许您添加MyClassAMyClassB类型的对象。您不能将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>();