How is Java unable to interpret this code:
private <T> Class<T> getClass(T object) {
return object.getClass();
}
I’m trying to visualise this and when I substitute in for an exmaple
private Class<String> getClass(String s) {
return s.getClass();
}
I get the same sort of error: required type <String> provided type <? extends String>. I’ve seen code that gets around this error by doing:
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) object.getClass();
What does this mean? What am I not understanding about this generics problem?
>Solution :
getClass follows some specific rules that are a bit unusual. The declared return type of Object::getClass is simply Class<?>, i.e. a class of some type. But as per the docs
The actual result type is
Class<? extends |X|>where |X| is the
erasure of the static type of the expression on whichgetClassis
called.
The erasure for T in your example is simply Object, so the return is Class<? extends Object>. Everything extends Object, so that’s the same as Class<?>.
When the parameter is the specific type String, the erasure is also String, and the result is Class<? extends String>.
Oracle tutorial on type erasure
I guess what happens under the hood is that the compiler effectively "overrides" Object::getClass with a more specific return type. Child classes are allowed to return more specific types than their parents, but not less specific. Consider this valid code:
class Foo {
public Class<? extends List<?>> foo() { return null; }
}
class Bar extends Foo {
@Override
public Class<? extends ArrayList<?>> foo() { return null; }
}
Because of how this is implemented, T obj; obj.getClass(); will return Class<?>, rather than what you’re expecting which is Class<? extends T>.
In your case, the cast is safe.