Question

Say I have the following class structure

public abstract class MyClass{}

public class MyClassA extends MyClass{}

public class MyClassB extends MyClass{}

How do I create a list of MyClass elements that contains both MyClassA and MyClassB elements without objections?

e.g.

    List<MyClass> myList = new LinkedList<MyClassA>();
Was it helpful?

Solution

Depending on your needs you have several options. You can either use plain List<MyClass> type objects. This allows you to add objects of types MyClassA and MyClassB. You can't set a List type object to a variable whose type is List<MyClass>. This is due to a concept called variance. Three types of variance exist in most programming languages that support generics (parametrized polymofism).

Invariance

Invariance does not allow one to deviate from a type in either direction. This is the case with generics in Java by default and that's why you can't assign a List<MyClassA> to a variable of List<MyClass>. Imagine the following scenario:

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

Covariance

Covariance allows you to use a the designated parameter type or any subtype thereof. In Java, you use the extends keyword to designate covariance: List<? extends MyClass>. It is allowed to assign a List type object into such a variable. With covariance, however, you can not add any objects to your generic object instance without an explicit cast. That is you can not do the following:

List<? extends MyClass> list = new LinkedList<MyClassA>();
list.add(new MyClassA());

This is only logical. After all, you can not know exactly what type of a List you are dealing with. It might as well be a List<MyClassB>.

Contravariance

Contravariance is the opposite of covariance and is designated using the super keyword: List<? super MyClassA>. It is allowed to assign a List<MyClass> (but not a List<MyClassB>) type object into such a variable. With contravariance you can add any subtype of the designated type parameter (lower limit in the type hierarchy). That is, it's allowed to do the following:

List<? super MyClass> list = new LinkedList<MyClass>();
list.add(new ChildA());

You can not, however, know exactly what type of a List the object is. That is you can only direclty assign an object stored in the list into a variable of type Object without an explicit cast:

Object o = list.get(0);
if (o instanceof MyClassA) {
  MyClassA mca = (MyClassA) o;
  //...
}

I hope this helps to clarify things a bit.

OTHER TIPS

Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object. A parent class reference can hold the objects of any of its subclasses. So a collection of a parent can hold the child classes objects. For example:

 List<MyClass> myClassList = new ArrayList<MyClass>();

You can use wildcards like List<? extends MyClass> myList = new ArrayList<MyClassA>(); but that will only let you get items from the list. Adding items is not safe since you can't know what's the underlying type of the List. You will have to add your items to the actual instance of your list directly like:

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.

Use List interface to implement your concrete/abstract classes. Something like this.

List<MyClass> list = new ArrayList<MyClass>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top