java:如何修复 Unchecked cast 警告

Posted

技术标签:

【中文标题】java:如何修复 Unchecked cast 警告【英文标题】:java: How to fix the Unchecked cast warning 【发布时间】:2010-12-08 13:35:40 【问题描述】:

我有以下代码:

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

为了防止出现此警告,我缺少什么?

【问题讨论】:

【参考方案1】:

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

换行:

T result = (T)store.get(e);

到:

T result = exampleClass.cast(store.get(e));

【讨论】:

@Mark Peters 在程序员说服自己的大多数问题中,他们通常是错误的。 我不认为所有图书馆设计师都是这样,如果是这样,他们就不应该编写图书馆。 API 中有未经检查的强制转换示例。 Collections.emptyList() 浮现在脑海中。 如果它展示了如何为泛型类型(你不能)做 Class.cast 会更有帮助。或者提供一些关于 Class.cast 如何在这种情况下远程应用的见解。如果有一个可以生成 Class.cast 的通用类型,那么使用 "? extends BaseClass" 代替 BaseClass.cast 不是更明智,因为这会强制要求基类对参数以及内部和返回值? @RobinDavies 这超出了所提问题的范围。 (如果您确实需要那种东西,那么您就已经偏离了滑雪道。至于使用通配符:它是一个Class 对象,因此不直接相关。在方法类型参数上,它只会混淆事物。没有必要调用方法时指定类型参数,通配符将被捕获就好了。) @RobinDavies exampleClass 来自原始问题。【参考方案2】:

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

@SuppressWarnings("unchecked")
T result = (T)store.get(e);

并添加说明为什么可以安全忽略警告。

【讨论】:

忽略是不安全的。让我们假设一个简单的例子:abstract class Animal public abstract void makeNoice(); class Cat extends Animal class Dog extends Animal DogCat 都是 Animal(当然是)。现在:class SomeAnimalUtils public static void makeNoise (Animal animal) Dog dog = (Dog) animal; dog.makeNoice(); 。让我们假设两者都正确实现了该方法。现在SomeAnimalUtils.makeNoise() 可能需要一个Cat,因为它扩展了想要的Animal,但它不能转换为Dog,你可以使用ClassCastException 好吧,我的例子在这里很愚蠢,但它应该表明您确实需要处理未经检查的强制转换。为了防止人们在中提供Cat,但只提供Dog(可能是TerrierHusky 等其他人的超类)。但是如果有人在JVM 中意外提供Cat,则会引发异常。这很糟糕,因为这意味着SomeAnimalUtils的程序员没有检查参数并自行抛出异常。 所以你需要预先检查一下。为此,请在 unsafe/unchecked cast 之前添加以下代码:if (null == animal) throw new NullPointerException("Parameter 'animal' is null"); else if (!(animal instanceof Dog)) throw new ClassCastException("Parameter 'animal'="+animal.toString()+" is not instance of Dog"); 。在这里,您还(必须)处理 Java 语言允许作为“对象”参数(= Object 或任何接口的实例)传递的空引用检查。如果你不处理空引用,你可能会在这里冒着臭名昭著的NPE 的风险。 仍然是主题:一个好的做法是让所有公共方法检查它们的“对象”参数以获取空引用和有效数据范围,例如来自数据库的 ID 号通常不能低于1。 ;-) @Roland:你说得对,忽略警告应该小心。这种转换是否保存的分歧取决于方法的用例及其上下文,在这种情况下,它几乎取决于用于将值放入映射中的方法。此方法未在问题中列出。因此除了作者之外没有人可以判断。【参考方案3】:

extends 在泛型中并不是这样工作的。 T != ? extends Component 即使T extends Component。你所拥有的其实是一个wildcard capture,它有不同的用途。

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

    private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores;

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

请记住,泛型类型仅在编译时解析,因此在运行时m_componentStores 无法知道您在其中拥有的值的确切类型,除此之外它extendsComponent

所以你从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;

【讨论】:

是否在运行时检查演员表?

以上是关于java:如何修复 Unchecked cast 警告的主要内容,如果未能解决你的问题,请参考以下文章

怎样消除unchecked警告

如何修复 UnhandledPromiseRejectionWarning: CastError: Cast to number failed for value "undefined&qu

java中遇到-xlint:unchecked,如何使用?求高手指教!

如何使用 -Xlint:unchecked 重新编译?

如何修复此异常;ClassCastException 引起:com.sun.proxy.$Proxy31 cannot be cast to javax.ws.rs.Produces

在 java 中使用“@SuppressWarnings("unchecked")”有啥好处?