Reputation: 9223
I've got the following code:
private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores;
public <T extends Component> T getComponent(Entity e, Class<T> exampleClass)
{
HashMap<Entity, ? extends Component> store = m_componentStores.get(exampleClass);
T result = (T)store.get(e);
if (result == null)
{
throw new IllegalArgumentException( "GET FAIL: "+e+" does not possess Component of class\nmissing: "+exampleClass );
}
return result;
}
When I compile, it shows that T result = (T)store.get(e)
has an unchecked cast.
Type safety: Unchecked cast from capture#2-of ? extends Component to T
What am I missing to prevent this warning from appearing?
Upvotes: 39
Views: 67205
Reputation: 85521
extends
in generics doesn't really work that way. T
!= ? extends Component
even though T extends Component
. What you have is in fact a wildcard capture, it has a different purpose.
And yes your solution is not type-safe - there is no relation between the two ?
marks in:
private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores;
So it becomes legal to put an instance of some subclass of Component
in this structure using some other class (not even a subclass of Component
) as the key.
Remember that generic types are resolved at compile time only, so at run time m_componentStores
has no way of knowing what exact type of the value you have in there, other than that it extends
Component
.
So the type you get from store.get(e)
is ... Component
:
Component result = store.get(e);
When you cast Component
to T
, the compiler issues a warning because the cast cannot be checked statically. But if you're sure of the semantics of your data structure, you can simply suppress the warning.
@SuppressWarnings("unchecked")
T resultT = (T)result;
PS: You don't need a wildcard capture, the following will work exactly the same in your case:
private HashMap<Class<?>, HashMap<Entity, Component>> m_componentStores;
Upvotes: 6
Reputation: 120861
Write @SuppressWarnings("unchecked")
above the Cast statement:
@SuppressWarnings("unchecked")
T result = (T)store.get(e);
And add a explanatory statement why it is safe to ignore the warning.
Upvotes: 17
Reputation: 147164
Class.cast
is what you want. Well, you might consider not using reflection.
Change the line:
T result = (T)store.get(e);
to:
T result = exampleClass.cast(store.get(e));
Upvotes: 53