tags:

views:

428

answers:

2

I have a piece of code that I think should compile, but it doesn't. Here is the code:

public class Program {
public void myMethod(List<EnumMap<? extends MyInterface, String>> map)
{

}

public void caller()
{
 EnumMap<MyEnum, String> map = new EnumMap<MyEnum, String>(MyEnum.class);

 List<EnumMap<MyEnum, String>> list = new LinkedList<EnumMap<MyEnum, String>>();

 myMethod(list); //error argument type is not compatible 

}

}

MyEnum is an enum that implements MyInterface.

Why does calling myMethod(list) gives me argument type is not compatible?

If I change myMethod's signature to:

public void myMethod(List<? extends Map<? extends MyInterface, String>> map)

then everything works fine, but I'm still puzzled and wish to know why the original method signature does not work.

+2  A: 

So, given

enum MyEnum implements MyInterface { ...}
...
List<EnumMap<MyEnum, String>> as = new ArrayList<EnumMap<MyEnum, String>>();
List<EnumMap<? extends MyInterface, String>> bs;

We should be able to assign bs = as?

Now suppose

enum OtherEnum implements MyInterface { XXX }
...
EnumMap<OtherEnum, String> otherMap =
    new EnumMap<OtherEnum, String>(OtehrEnum.class);
otherMap.put(OtherEnum.XXX, "");
bs.set(0, otherMap);
EnumMap<MyEnum, String> myMap = as.get(0);
MyEnum xxx = myMap.keys().iterator().next();

otherMap and myMap point to the same object but clearly different types. Worse, xxx is of tyoe MyEnum but is pointing to an object of type OtherEnum.

Pointers to pointers in the presence of polymorphism is difficult.

Tom Hawtin - tackline
Thanks, I understand what you are saying, but how come changing method signature to public void myMethod(List<? extends Map<? extends MyInterface, String>> map) makes the error go away? Shouldn't the error stay?
Alvin
+1  A: 

EnumMap<MyEnum, String> and EnumMap<? extends MyInterface, String> are different types (the former is a subtype of the latter). So List<EnumMap<MyEnum, String>> and List<EnumMap<? extends MyInterface, String>> are not compatible with each other. In general, List<A> cannot be assigned to List<B> if A and B are different types, no matter what the relationship between A and B is (same applies to any generic type not just List). When you have a bounded type parameter, that is a different story; the compatibility takes the bounds into consideration.

newacct