Rohan Prabhu Rohan Prabhu - 2 months ago 23
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
? 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)
, so when called with
? extends R
, which let's say is
, but since
now returns
, assigning it to type
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
is available, but
is? Which still doesn't make sense because isn't this purely checked during the compile phase alone?

So, it turns out that
Class<? extends |X|>
and not
Class<? extends X>
, where
is the erasure of
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: (I tried taking a screenshot, but the pop-up kept on going away).


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>.