Type safety: Unchecked cast from Object

落爺英雄遲暮 提交于 2019-11-28 06:12:45
Jon Skeet

Yes - this is a natural consequence of type erasure. If o is actually an instance of Action<String> that won't be caught by the cast - you'll only see the problem when you try to use it, passing in a ClientInterface instead of a string.

You can get rid of the warning using:

@SuppressWarnings("unchecked")

as a function annotation, but you can't easily sort out the underlying problem :(

As usual, Jon Skeet is right.

To elaborate on the not-easily part of his answer:

Given

class ClientAction implements Action<ClientInterface> {}

You can write:

Class<? extends Action<ClientInterface>> c = ClientAction.class;
Action<ClientInterface> action = c.newInstance();

This eliminates both the cast and the warning, at the price of introducing a non-generic type so you can use .class to get a sufficiently accurately typed Class object.

The warning means that the compiler can't guarantee type safety even if the casting works fine at runtime. Due to erasure, at runtime the casting is simply a casting to Action. It is possible that the underlying generic class is not of type ClientInterface as expected. In this case, the problem will appear later (maybe even much later), as a ClassCastException.

In this specific case I recommend suppressing this specific warning by the following compiler directive:

@SuppressWarnings("unchecked")

Don't worry about. It is because the Java compiler has no way to know, what is the real type of the object.

You've lost the type information because of erasure (i.e., the parameterised types have been erased), hence the warning. You can't do anything about it, other than clean up the surrounding code so that generics are used more frequently, so you can pass the generic type information and avoid casting at all.

This is a downcast. It's the dynamic cast where the compiler has no idea of the actual object the reference is pointing to.

You get this warning because the target type of the cast Action<ClientInterface> is a parameterized type and the compiler cannot guarantee that the object being type casted is of the same type.

If you don't want to suppress this warning and don't care about the type parameter, you could change the code to this by using wildcards:

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();
 }
 [...]

This is much safer because the instanceof can't check that o is a object of Action<ClientInterface>, it just check if o is a object of Action since further generic type information will be erased at runtime.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!