Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

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

like image 511
Rohan Prabhu Avatar asked Nov 15 '16 08:11

Rohan Prabhu


1 Answers

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

like image 134
Andy Turner Avatar answered Nov 01 '22 04:11

Andy Turner