Ответ 1
Class.cast
- это то, что вы хотите. Ну, вы можете не использовать отражение.
Измените строку:
T result = (T)store.get(e);
в
T result = exampleClass.cast(store.get(e));
У меня есть следующий код:
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;
}
Когда я компилирую, он показывает, что T result = (T)store.get(e)
имеет неконтролируемый отбор.
Type safety: Unchecked cast from capture#2-of ? extends Component to T
Что мне не хватает, чтобы предотвратить появление этого предупреждения?
Class.cast
- это то, что вы хотите. Ну, вы можете не использовать отражение.
Измените строку:
T result = (T)store.get(e);
в
T result = exampleClass.cast(store.get(e));
Напишите @SuppressWarnings("unchecked")
над выражением Cast:
@SuppressWarnings("unchecked")
T result = (T)store.get(e);
И добавьте пояснительное выражение о том, почему безопасно игнорировать предупреждение.
extends
в дженериках на самом деле не работает. T
!= ? extends Component
, хотя T extends Component
. То, что у вас есть на самом деле подстановочный знак, имеет другую цель.
И да, ваше решение не является безопасным по типу - между двумя метками ?
нет связи:
private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores;
Таким образом, становится законным помещать экземпляр некоторого подкласса Component
в эту структуру, используя в качестве ключа какой-либо другой класс (даже не подкласс Component
).
Помните, что общие типы разрешаются только во время компиляции, поэтому во время выполнения m_componentStores
не имеет способа узнать, какой именно тип значения у вас есть, кроме того, что он extends
Component
.
Итак, тип, который вы получаете из store.get(e)
,... Component
:
Component result = store.get(e);
При нажатии Component
на T
компилятор выдает предупреждение, потому что приведение не может быть проверено статически. Но если вы уверены в семантике вашей структуры данных, вы можете просто подавить предупреждение.
@SuppressWarnings("unchecked")
T resultT = (T)result;
PS: Вам не нужен захват подстановки, в вашем случае будет работать то же самое:
private HashMap<Class<?>, HashMap<Entity, Component>> m_componentStores;