Brad
Brad

Reputation: 9223

java: How to fix the Unchecked cast warning

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

Answers (3)

rustyx
rustyx

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

Ralph
Ralph

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

Tom Hawtin - tackline
Tom Hawtin - tackline

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

Related Questions