Rohan Prabhu Rohan Prabhu - 18 days ago 10
Java Question

Why does a wildcard on a generic parameter require an explicit cast?

I have a function:

<T> T get(Class<T> fetchType) {
...
}


So, if I were to do something like:

String x = get(String.class);


this is all good.

However, in another function:

<R> R otherFunction(R base) {
return get(base.getClass());
}


Gives me an error, because
base.getClass()
returns
? extends R
.

reason: no instance(s) of type variable(s) exist so that capture of ? extends Object conforms to R
inference variable T has incompatible bounds:
equality constraints: capture of ? extends Object upper bounds: Object, R


Now from what I understand, the function
get(Class<T> x)
returns
T
, so when called with
? extends R
, which let's say is
CAP#1
, but since
get
now returns
CAP#1
, assigning it to type
R
should not be a problem. To test this, I tried:

Class<? extends CharSequence> stringClass = String.class;
CharSequence x = get(stringClass);


This seems to work without any issues. What's going wrong?

EDIT: Is this because of type-erasure, that at runtime no information about
R
is available, but
CharSequence
is? Which still doesn't make sense because isn't this purely checked during the compile phase alone?

So, it turns out that
Object.getClass()
returns
Class<? extends |X|>
and not
Class<? extends X>
, where
|X|
is the erasure of
X
which is why it works for concrete types (like
? extends CharSequence
, but not for a generic type). IntelliJ probably does not report it accurately, which caused the confusion: http://i.imgur.com/yE8LswM.jpg (I tried taking a screenshot, but the pop-up kept on going away).

Answer

The reason is described in the Javadoc of Object.getClass:

public final Class<?> getClass()

The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called.

So, when you call base.getClass(), the actual result is Class<?>, since the erasure of R is Object. It's not Class<? extends R>.

Comments