I noticed something while I was derping around with generics. In the example below, doStuff1
compiles but doStuff2
doesn't:
public <T extends Foo> void doStuff1(T value) {
Class<? extends Foo> theClass = value.getClass();
}
public <T extends Foo> void doStuff2(T value) {
Class<? extends T> theClass = value.getClass();
}
So, I looked up the documentation for Object.getClass()
and found this:
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.
This made me a bit curious. Why is getClass()
designed this way? I can understand converting types to their raw classes if applicable, but I see no obvious reason why they'd necessarily have to make it also kill off T
. Is there a specific reason why it also gets rid of it, or is it just a general "let's just get rid of everything because it's easier; who would ever need it anyway" approach?
If getClass()
returns Class<? extends X>
, nothing really bad can happen; actually it'll help a lot of use cases.
The only problem is, it is not theoretically correct. if an object is an ArrayList<String>
, its class
cannot be Class<ArrayList<String>>
- there is no such class, there is only a Class<ArrayList>
.
This is actually not related to erasure. If one day Java gets full reified types, getClass()
should still return Class<? extends |X|>
; however there should be a new method, like getType()
which can return a more detailed Type<? extends X>
. (though, getType
may conflict with a lot of existing classes with their own getType
methods)
For the timing being, since Class<? extends X>
might be useful in a lot of cases, we can design our own method that does that
static <X> Class<? extends X> myGetClass(X x){ ... }
but it's understandable they wouldn't put this kind of hack in standard lib.