8

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

Rohan Prabhu
  • 7,180
  • 5
  • 37
  • 71

2 Answers2

7

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

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
0

Your parameter R base will allow all objects of your desired generic class < R >, but also all objects, which are subclasses of < R > can be put into this method. Because of this, you don't know what will happen if you call base.getClass(), you expect < R > but it could also be a class wich extends generic R.

Jeroen van Dijk-Jun
  • 1,028
  • 10
  • 22
  • But the example of the `String` (which is a subclass of `CharSequence`) works. – Thilo Nov 15 '16 at 08:46
  • Yes, because you said it extended charsequence. All possible subclasses you can make of String, still are also classes which extend charsequence. – Jeroen van Dijk-Jun Nov 15 '16 at 08:50
  • 1
    Which is fine, it of course could be any class which extends `R`, but that class would still be `assignable` to R, which seems to work perfectly fine when I do `? extends CharSequence`. It accepts, `String`, but any instance of `String` is still assignable to `CharSequence`. – Rohan Prabhu Nov 15 '16 at 08:52