user1534960
user1534960

Reputation: 21

Trouble with generics and variable assignment

I have two maps Something1 and Something2. Both extend the Class Something.

Map<Class<? extends Something1>, String> m1
Map<Class<? extends Something2> ,String> m2

I want to create a more generic map m3 to which I can assign m1 or m2 like this:

Map<Class<? extends Something>, String> m3 = m1;

However I get the following exception:

Type mismatch: cannot convert from Map<Class<? extends Something1>, String> to Map<Class<? extends Something>, String>

I also tried using Class<?> but it doesn't seem to work.

What am I doing wrong ?

Upvotes: 2

Views: 65

Answers (2)

newacct
newacct

Reputation: 122449

Non-wildcard type arguments must be exactly the same to be compatible. Class<? extends Something1> is not exactly the same as Class<? extends Something> (even though one is a subtype of the other), and therefore, a Map of one is not compatible with a Map of the other.

If you want a type that can accept Maps with different type arguments, you need a wildcard at the top level (though note that this will effectively make the Map read-only):

Map<? extends Class<? extends Something>, String> m3 = m1;

Upvotes: 0

wassgren
wassgren

Reputation: 19221

That is not possible. Consider the following:

Map<Class<? extends Something1>, String> m1 = new HashMap<>();
m1.put(Something1.class, "Something1"); // OK
m1.put(Something2.class, "Something2"); // Error

So, you can't put Something2 as the key.

The other way around:

Map<Class<? extends Something2>, String> m2 = new HashMap<>();
m2.put(Something1.class, "Something1"); // Error
m2.put(Something2.class, "Something2"); // OK

Here, you can't put Something1 as the key.

But, if you create a version that uses the base class as the wildcard it works. Check this out:

Map<Class<? extends Something>, String> m = new HashMap<>();
m.put(Something1.class, "Something1"); // OK
m.put(Something2.class, "Something2"); // OK

Your problem is then that you are trying to assign a more specific type to the generic type. Like this:

m = m1; // Boom, but why?

Why does that not work. Well, it is because if you allow that assignment you would be able to do this:

m.put(Something2.class, "Something2"); 

Which obviously would not be ok since then you would put Something2 as the key for a Something1-type Map.

Upvotes: 2

Related Questions