views:

41

answers:

2

Suppose I have MyEdge and MyEdgeModified, such that MyEdge is the superclass and MyEdgeModified is the subclass. Now, suppose I do this:

List<List<MyEdge>> collectionOfEdgeLists = new LinkedList<List<MyEdge>>();
for(int i = 0; i < someValue; i++) {
    List<MyEdgeModified> newList = someMethod();
    collectionOfEdgeLists.add(newList); //ruh roh
}

Now, if I do this:

private List<MyEdge> convert(final List<MyEdgeModified> list) {
     final List<MyEdge> otherList = new ArrayList<MyEdge>(list.size());
     for(Edge edge : list) {
         otherList.add(edge);
     }
     return otherList;
}

Then:

collectionOfEdgeLists.add(convert(newList)); //ok...

Now, the problem I'm seeing here is that I can treat each individual MyEdgeModified as an Edge, but if I have a collection I have to first build a whole 'nother list to be able to use it. Why? Am I doing something wrong? This seems wrong and dumb to me.

+2  A: 

This is due to the absence of covariance in Java generics.

Covariance means that for some type T and subtype S, List<S> is a subtype of List<T>.

This is not the case in Java. For the reasoning, assume that covariance exists and consider the following case:

List<String> stringList = new ArrayList<String>();
List<Object> oList = stringList; // Just referring to a subtype as its supertype
oList.add(new Object()); // nothing wrong with adding an Object to a List<Object>
for (String s : stringList) { ... }  // now what?
danben
+3  A: 

Consider this code:

List<MyEdgeModified> modifiedList = new List<MyEdgeModified>();

// This is what you want to do, but which doesn't work
List<MyEdge> edgeList = modifiedList;

// Now this would have to be valid...
edgeList.add(new MyEdge());

// And this should be valid too...
MyEdgeModified modified = modifiedList.get(0);

... but you've managed to put a reference to an instance of MyEdge into a List<MyEdgeModified> - so you've managed to break type safety.

That's what the rules are there to prevent.

Now what you can do is use wildcards:

List<MyEdgeModified> modifiedList = new List<MyEdgeModified>();
List<? extends MyEdge> edgeList = modifiedList;

At that point, you won't be able to add to edgeList, but you can take items from it... so all is safe.

Now creating a List<List<? extends MyEdge>> ends up being trickier again... I can't remember offhand whether it's even allowed...

In general, the best place to look for details of this sort of thing is Angelika Langer's Java Generics FAQ.

Jon Skeet