Reputation: 429
I have the following code:
public final <T extends Component> T getComponent(Class<T> type) {
Iterator<Component> it = components.iterator();
while(it.hasNext()) {
Component next = it.next();
if(type.isAssignableFrom(next.getClass()))
return (T)next; // Why is this an unchecked cast from Component to T?
}
return null;
}
And for some reason, return (T)next;
is an unchecked cast from Component to T.
I'm not sure as to why this is, because T has to extend Component, it should be able to safely cast it to any subclasses of Component, right?
If I manually do return (TestComponent)next;
and change the return type to TestComponent it works fine, so why doesn't it work with T?
Upvotes: 8
Views: 4060
Reputation: 53694
Others have described the problem, here is the solution with cleaner test:
if (type.isInstance(next)) {
return type.cast(next);
}
Upvotes: 15
Reputation: 37645
It's an unchecked cast because the compiler cannot be sure that next
is a T
. All it knows is that it's a Component
.
As for your question about why casting to a T
generates the warning, but not casting to a TestComponent
, that's a lot more subtle. Casting to a TestComponent
is inherently less dodgy than casting to a T
. If test
is not a TestComponent
, the cast to a TestComponent
would cause a ClassCastException
at runtime. But this isn't the case for casting to a T
because the type T
is not known at runtime, due to type erasure. If you cast a Component
that is not a T
to a T
and then add the result into a List<T>
, you would have a List<T>
where not all of the items are T
s. This would break the guarantee that generics are supposed to provide. There would be no chance of a ClassCastException
preventing this.
In your case, you don't need to worry. You have checked the cast to a T
is safe by passing the Class<T>
object and doing the check. You have two choices. You could suppress the warning and add a comment explaining why it's safe to do so. However, a better alternative would be to write return type.cast(next);
instead. This doesn't generate a warning because type.cast(object)
would throw a ClassCastException
if object
were not a T
.
Upvotes: 4
Reputation: 1620
As T is a subclass of Component, every T is a Component but not every Component is a T.
If a subclass inherits from a superclass, casting the superclass to the subclass cannot be performed successfully.
Therefore a new Component cannot be cast to a T instance.
Upvotes: 1