java:如何修复未选中的强制转换警告

Bra*_*rad 24 java generics casting

我有以下代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

当我编译时,它显示T result = (T)store.get(e)有一个未经检查的强制转换.

Type safety: Unchecked cast from capture#2-of ? extends Component to T
Run Code Online (Sandbox Code Playgroud)

为防止出现此警告,我错过了什么?

Tom*_*ine 38

Class.cast是你想要的.好吧,你可能会考虑不使用反射.

换行:

T result = (T)store.get(e);
Run Code Online (Sandbox Code Playgroud)

至:

T result = exampleClass.cast(store.get(e));
Run Code Online (Sandbox Code Playgroud)

  • @Mark Peters在程序员说服自己的大多数问题中,他们通常都是错的. (3认同)
  • 我不认为这对所有的图书馆设计师都是如此,如果是这样的话他们不应该写图书馆.API中有未经检查的强制转换的示例.想到`Collections.emptyList()`. (3认同)
  • 如果它展示了如何对泛型类型执行 Class.cast(您不能),则会更有帮助。或者提供一些有关 Class.cast 如何在此类情况下远程应用的见解。如果存在可以生成 Class.cast 的通用类型,那么使用“? extends BaseClass”而不是 BaseClass.cast 不是更明智吗,因为这强制要求参数以及内部和内部参数都必须满足基类要求。返回值? (3认同)
  • @RobinDavies `exampleClass` 来自原始问题。 (2认同)

Ral*_*lph 16

@SuppressWarnings("unchecked")在Cast语句上面写:

@SuppressWarnings("unchecked")
T result = (T)store.get(e);
Run Code Online (Sandbox Code Playgroud)

并添加一个解释性声明,为什么忽略警告是安全的.

  • 忽视是不安全的。让我们假设一个简单的例子:`abstract class Animal { public abstract void makeNoice(); }`、`class Cat extends Animal { }` 和`class Dog extends Animal {}`。`Dog` 和 `Cat` 都是 `Animal`(肯定是)。现在:`class SomeAnimalUtils { public static void makeNoise (Animal Animal) { Dog dog = (Dog) animal; dog.makeNoice(); } }`。让我们假设两者都正确实现了该方法。现在,`SomeAnimalUtils.makeNoise()` 可能需要一个 `Cat`,因为它扩展了想要的 `Animal`,但它不能被转换为 `Dog`,并且你捕获了 `ClassCastException`。 (2认同)

rus*_*tyx 6

extends在泛型中并不是这样工作的。T!=? extends Component即使T extends Component. 你所拥有的实际上是一个通配符捕获,它有不同的目的。

是的,您的解决方案不是类型安全的 - 两个标记之间没有关系?

    private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores;
Run Code Online (Sandbox Code Playgroud)

Component因此,使用其他类(甚至不是 的子类Component)作为键将 的某个子类的实例放入此结构中是合法的。

请记住,泛型类型仅在编译时解析,因此在运行时 m_componentStores无法知道其中的值的确切类型,除了 it extends Component

所以你得到的类型store.get(e)是...... Component

    Component result = store.get(e);
Run Code Online (Sandbox Code Playgroud)

当您转换Component为时T,编译器会发出警告,因为无法静态检查转换。但是,如果您确定数据结构的语义,则可以简单地抑制警告。

    @SuppressWarnings("unchecked")
    T resultT = (T)result;
Run Code Online (Sandbox Code Playgroud)

PS:您不需要通配符捕获,以下内容在您的情况下将完全相同:

    private HashMap<Class<?>, HashMap<Entity, Component>> m_componentStores;
Run Code Online (Sandbox Code Playgroud)