Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a Generic type containing a Generic type be assigned to a Generic typed class of wildcard type

Tags:

java

generics

Sorry if the title seems confusing, but some examples are in order.

Let's say I have some Java class with a generic type parameter:

public class GenericClass<T> {
}

I can create a variable typed to store an object, with the generic parameter set to, say a String. Java will also let me assign that variable to another variable but with the generic parameter set to the wildcard <?> type:

GenericClass<String> stringy = ...
GenericClass<?> generic = stringy; // OK

However, when working with a class with a generic parameter, if you set the type of that parameter to be generic, you can't then assign an object of that class to an identically typed/genericized type where the latter (inner/nested) parameter is of the wildcard type <?>:

GenericClass<GenericClass<String>> stringy = ...
GenericClass<GenericClass<?>> generic = stringy; // Compile Error

// And just in case that is confusing, a more
// realistic example involving Collections:
List<GenericClass<String>> stringy = ...
List<GenericClass<?>> generic = stringy; // Compile Error

The specific compile error is:

Type mismatch: cannot convert from List<GenericClass<String>> to List<GenericClass<?>>

Intuitively I would think that the assignment in question should not be a problem. So why is this assignment an problem?

like image 345
Adam Batkin Avatar asked Sep 25 '09 09:09

Adam Batkin


2 Answers

The problem your facing is denominated Covariance.

List<GenericClass<String>> stringy = ...
List<GenericClass<?>> generic = stringy;
generic.add(new GenericClass<Integer>());

If this wasn't a compile error, then the last line of code would be possible.

You could get around the error by doing this:

 List<? extends GenericClass<?>> generic = stringy;

but you can not use add also because you don't really know what ? extends GenericClass<?> is (Covariance once again). In this case you can only enumerate through the List and expect GenericClass<?>.

like image 117
bruno conde Avatar answered Sep 28 '22 01:09

bruno conde


Technically, that's because List<GenericClass<String>> is not a subtype of List<GenericClass<?>>. In order to make it work, you could do something like

List<? extends GenericClass<?>> generic = stringy

which should work as expected (though is pretty ugly...).

See, for example, this SO question for more details

like image 24
Dirk Avatar answered Sep 27 '22 23:09

Dirk