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
。 Dog
和 Cat
都是 Animal
(当然是)。现在:class SomeAnimalUtils public static void makeNoise (Animal animal) Dog dog = (Dog) animal; dog.makeNoice();
。让我们假设两者都正确实现了该方法。现在SomeAnimalUtils.makeNoise()
可能需要一个Cat
,因为它扩展了想要的Animal
,但它不能转换为Dog
,你可以使用ClassCastException
。
好吧,我的例子在这里很愚蠢,但它应该表明您确实需要处理未经检查的强制转换。为了防止人们在中提供Cat
,但只提供Dog
(可能是Terrier
或Husky
等其他人的超类)。但是如果有人在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
无法知道您在其中拥有的值的确切类型,除此之外它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;
【讨论】:
是否在运行时检查演员表?以上是关于java:如何修复 Unchecked cast 警告的主要内容,如果未能解决你的问题,请参考以下文章
如何修复 UnhandledPromiseRejectionWarning: CastError: Cast to number failed for value "undefined&qu
java中遇到-xlint:unchecked,如何使用?求高手指教!
如何修复此异常;ClassCastException 引起:com.sun.proxy.$Proxy31 cannot be cast to javax.ws.rs.Produces