I am not sure how to word the title of this question in a concise way. There are a few related questions I have found, for instance this one, but none of them seem to answer the question I have explicitly.
But essentially what I am asking is this:
Consider the following code
static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
A left = tuple.getLeft();
return left.getClass();
}
As is, this code does not compile. The compilation fails with the error
Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A>
I think this is essentially because getClass
returns a type Class<? extends Object>
but the compiler is expecting Class<? extends A>
.
A solution is to cast the class as follows:
static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
A left = tuple.getLeft();
return (Class<? extends A>) left.getClass();
}
This compiles. However, there is a warning because of an unchecked cast.
My question is, is the warning justified? Is there a legitimate reason not to do this? Or is this just a case where the compiler can't verify that it is correct, but it will always work as long as tuple.getLeft()
is indeed an instance of A
?
By the way, the Pair
class is this one, from the Apache commons library
x.getClass()
doesn't declare its return type asClass<? extends X>
anyway; especially since the compiler sometimes treats it as though it does. – MelinamelindaClass<A>
. I thinkextends
is wrong. If anything the class type should be a super class of A, not a sub class. – MicronutrientA
can hold an object at runtime of typeA
or any subtype ofA
. HenceClass<? extends A>
. – MelinamelindaA
is not a variable but a type parameter. Its type can only be A. (At least, without any constraints, I don't thinkA
will ever resolve to anything but itself.) – MicronutrientX
be taken from, though?getClass
is declared injava.lang.Object
– KazanPair<A,B>
thenleft
is expected to be an instance ofA
. But an instance ofA
might be a direct instance of some subtype ofA
. So its class would be? extends A
. – MelinamelindaClass<?>
; but its actual return type isClass<? extends X>
whereX
is whatever the type is of the reference you're callinggetClass()
on. – MelinamelindagetClass
isClass<? extends |T|>
, whereT
is the class or interface that was searched forgetClass
(§15.12.1) and|T|
denotes the erasure ofT
(§4.6)." The erasure point might be annoying but as my answer demonstrates, dropping that rule would result in unsafe code. – Praxiteles