The following Java method fails to compile:
<T extends Number> void foo(T t)
{
Class<? extends T> klass = t.getClass();
}
Error received is:
Type mismatch: cannot convert from Class<capture#3-of ? extends Number>
to Class<? extends T>
Can someone explain why Class<? extends T>
is invalid, but Class<? extends Number>
is fine?
Javadoc says:
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. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
It is kind of silly. It would have been better, for most use cases, if
x.getClass()
returnsClass<? extends X>
, instead of the erasedClass<? extends |X|>
.The erasure is the cause of loss of information, making your code, apparently safe, fail to compile.
t.getClass()
returnsClass<? extends |T|>
, and|T| = Number
, so it returnsClass<? extends Number>
.The erasure (mandated by the language spec) is to maintain theoretical correctness. For example
Although c2 seems very reasonable, in Java, there is really no such class for
List<String>
. There is only the class forList
. So allowing c2 would be, theoretically incorrect.This formality created lots of problem in real world usages, where programmers can reason that
Class<? extends X>
is safe for their purposes, but have to cope with the erased version.You can simply define your own
getClass
that returns the un-erased typeBecause the
T
class' type doesn't extend fromT
. Instead, it extends fromNumber
, exactly as you have declared yourself in<T extends Number>
. Simple as that.A better question would be:
The answer to that is that the
Object#getClass()
returnsClass<?>
with an unbounded wildcard?
because the object itself is not directly aware about its generic type which is been expected in an arbitrary method.