我尝试将一个对象强制转换为我的 Action 类,但它会导致警告:
Type safety: Unchecked cast from Object to Action<ClientInterface>
Action<ClientInterface> action = null;
try {
Object o = c.newInstance();
if (o instanceof Action<?>) {
action = (Action<ClientInterface>) o;
} else {
// TODO 2 Auto-generated catch block
throw new InstantiationException();
}
[...]
感谢您的帮助
是的 - 这是类型擦除的自然结果。如果
o
实际上是 Action<String>
的实例,不会被强制转换捕获 - 只有当您尝试使用它时,传入 ClientInterface
而不是字符串,您才会看到问题。
您可以使用以下方法消除警告:
@SuppressWarnings("unchecked")
作为函数注释,但你无法轻松解决底层问题:(
像往常一样,乔恩·斯基特是对的。
详细说明他的答案中不容易的部分:
鉴于
class ClientAction implements Action<ClientInterface> {}
您可以写:
Class<? extends Action<ClientInterface>> c = ClientAction.class;
Action<ClientInterface> action = c.newInstance();
这消除了强制转换和警告,但代价是引入非泛型类型,因此您可以使用
.class
来获得类型足够准确的 Class
对象。
该警告意味着即使转换在运行时正常工作,编译器也无法保证类型安全。由于擦除,在运行时转换只是对 Action 的转换。底层泛型类可能不是预期的 ClientInterface 类型。在这种情况下,问题将在稍后(甚至可能更晚)以 ClassCastException 的形式出现。
在这种特定情况下,我建议通过以下编译器指令抑制此特定警告:
@SuppressWarnings("unchecked")
不用担心。这是因为Java编译器无法知道对象的真实类型是什么。
这是一种沮丧。这是动态转换,编译器不知道引用指向的实际对象。
您收到此警告是因为转换的目标类型
Action<ClientInterface>
是一个参数化类型,并且编译器无法保证正在转换的对象属于同一类型。
如果您不想抑制此警告并且不关心类型参数,您可以使用通配符将代码更改为:
Action<?> action = null;
try {
Object o = c.newInstance();
if (o instanceof Action<?>) {
action = (Action<?>) o;
} else {
// TODO 2 Auto-generated catch block
throw new InstantiationException();
}
[...]
这更安全,因为
instanceof
无法检查o
是否是Action<ClientInterface>
的对象,它只是检查o
是否是Action
的对象,因为进一步的通用类型信息将被擦除在运行时。
由于擦除,您丢失了类型信息(即参数化类型已被擦除),因此出现警告。除了清理周围的代码以便更频繁地使用泛型之外,您对此无能为力,因此您可以传递泛型类型信息并完全避免强制转换。
现在你可以简单地做
if (o instanceof Action<ClientInterface> action) {
//now you can use action
}
如果 o 是实例 eof 动作,则该对象将自动转换为动作