Reputation: 133
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>();
Upvotes: 2
Views: 7222
Reputation: 11
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>.
This works for me as a type cast for a list
Upvotes: 0
Reputation: 5472
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 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 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 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.
Upvotes: 6
Reputation:
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.
Upvotes: 2
Reputation: 68715
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>();
Upvotes: 3
Reputation: 1263
Use List
interface to implement your concrete/abstract classes. Something like this.
List<MyClass> list = new ArrayList<MyClass>();
Upvotes: 0