在 Java 中从对象强制转换而不会收到未经检查的警告

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1774356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 22:30:02  来源:igfitidea点击:

Casting from Object in Java without getting an unchecked warning

javagenericscasting

提问by swampsjohn

I wrote a class that has a map of <String, Object>. I need it to hold arbitrary objects, but at the same time sometimes I need to cast some of those objects, so I'll do something like

我写了一个包含<String, Object>. 我需要它来保存任意对象,但同时有时我需要投射其中一些对象,所以我会做类似的事情

HashMap<String, Object> map = new HashMap<String, Object>();                                                                                 
Object foo = map.get("bar");                                                                                                                                                                                                         
if (foo instanceof HashMap) {                                                                                                                                                                                                        
    ((HashMap<String, Integer>) foo).put("a", 5);                                                                                                                                                                                    
}            

which gives the warning

这给出了警告

Stuff.java:10: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: java.util.HashMap<java.lang.String,java.lang.Integer>
        ((HashMap<String, Integer>) foo).put("a", 5);

I suspect it has to do with the use of generics. I can get rid of the error using @SupressWarnings("unchecked"), but I was wondering if there was a better way to do it. Or maybe the fact that I'm getting the warning means I should reconsider what I'm doing. Is there anything I could do, or should I just use @SupressWarnings?

我怀疑这与泛型的使用有关。我可以使用@SupressWarnings("unchecked") 消除错误,但我想知道是否有更好的方法来做到这一点。或者也许我收到警告的事实意味着我应该重新考虑我在做什么。有什么我可以做的,还是应该只使用@SupressWarnings?

采纳答案by ChssPly76

Edited(based on question clarification)

编辑(基于问题澄清)

Casting to HashMap<String, Integer>(btw, using Mapinstead of HashMapis arguably a better choice) is a different story. There's sadly no way to avoid an unchecked warning in that case due to type erasure. You can, however, use it as non-generic map:

投射到HashMap<String, Integer>(顺便说一句,使用Map而不是HashMap可以说是更好的选择)是一个不同的故事。遗憾的是,由于类型擦除,在这种情况下无法避免未经检查的警告。但是,您可以将其用作非通用映射:

if (foo instanceof Map) {                                                                                                                                                                                                        
  ((Map) foo).put("a", 5);                                                                                                                                                                                    
}

You'll obviously have to cast on "gets" and you lose (perceived) type safety but there'll be no unchecked warning.

显然,您必须使用“gets”,并且会丢失(感知到的)类型安全性,但不会有未经检查的警告。



There must be more to this story. The following code:

这个故事肯定还有更多。以下代码:

Map<String, Object> map = Maps.newHashMap(); // or new HashMap<String, Object>();
Object foo = map.get("bar");
if (foo instanceof Widget) {
  ((Widget) foo).spin();
}

does NOTgenerate an unchecked warning for me. Nor can I imagine why would it. If you know beforehand that "bar" would always return a widget, doing this:

确实产生对我来说是未经检查的警告。我也无法想象为什么会这样。如果您事先知道“bar”将始终返回一个小部件,请执行以下操作:

Widget widget = (Widget) map.get("bar");
widget.spin();

would work perfectly fine as well. Am I missing something here?

也能正常工作。我在这里错过了什么吗?

回答by BalusC

Or maybe the fact that I'm getting the warning means I should reconsider what I'm doing.

或者也许我收到警告的事实意味着我应该重新考虑我在做什么。

You got the point. Logical step would be to create a Map<String, Widget>instead of a Map<String, Object>. If that's not an option for some reason, you could do something like:

你明白了。逻辑步骤是创建一个Map<String, Widget>而不是一个Map<String, Object>. 如果由于某种原因这不是一个选项,您可以执行以下操作:

Widget w = Widget.class.cast(foo);
w.spin();

This doesn't give a compiler warning anymore, but this still doesn't necessarily mean that your Mapof mixed objects is a good practice.

这不再发出编译器警告,但这仍然并不一定意味着您Map的混合对象是一个好习惯。

Edit: as ChssPly76 pointed out, this should actually not have generated an "unchecked cast" warning. I tested it in Eclipse and it indeed didn't gave the particular warning. Can you post an SSCCE(a class with a main()purely demonstrating the problem) so that we can better understand what's going on?

编辑:正如 ChssPly76 指出的那样,这实际上不应该产生“未经检查的强制转换”警告。我在 Eclipse 中对其进行了测试,它确实没有给出特定警告。您能否发布一个SSCCE(一个main()纯粹演示问题的课程),以便我们更好地了解发生了什么?

Edit 2: so you're using a map which may contain generic structures such as maps. That explains the bit. Well, aside from redesigning the structure, I don't see any other option than just live with the @SuppressWarnings("unchecked")annotation.

编辑 2:所以您使用的地图可能包含诸如地图之类的通用结构。这解释了这一点。好吧,除了重新设计结构之外,我看不到任何其他选择,只能忍受@SuppressWarnings("unchecked")注释。

回答by Ross

If your Mapis holding objects of the same type (e.g. all Widgets), then you can use Map<String,Widget>to eliminate both the cast and the warning.

如果您Map持有相同类型的对象(例如所有小部件),那么您可以使用Map<String,Widget>来消除强制转换和警告。

If you're holding objects of arbitrary type, however, then this shows you have a deeper design problem. If you know what type the object will be based on the name (e.g. "bar" always gets you a Widget) then consider using an object with a method called Widget getBar()rather than a Map.

但是,如果您持有任意类型的对象,那么这表明您有更深层次的设计问题。如果您知道对象将基于名称的类型(例如,“bar”总是为您提供一个 Widget),那么请考虑使用一个带有调用方法Widget getBar()而不是Map.

If you don't know what "bar" will be when you get it from the map, you have an even deeper design problem and should consider using some Object Oriented principles to reduce coupling.

如果你不知道当你从地图上得到它时“bar”是什么,你有一个更深层次的设计问题,应该考虑使用一些面向对象的原则来减少耦合。

回答by Droo

Not sure how you're using the objects, but there's:

不确定您如何使用这些对象,但有:

for(Map.Entry<String, Widget> entry = map.entrySet())
{
     entry.getValue().spin();
}

回答by Titi Wangsa bin Damhore

i think the underlying problem is the Object class

我认为潜在的问题是 Object 类

HashMap<String, Object> map;

if you want to remove the casting warning, then you need to specify a base class / interface.

如果要删除强制转换警告,则需要指定基类/接口。

for example you could do do this

例如你可以这样做

Map<String, Animal> map = new LinkedHashMap<String, Animal>(); 
Animal pet = map.get("pet"); 
pet.feed();

instead of

代替

Map<String, Object> map = new LinkedHashMap<String, Object>();
Object pet = map.get("pet");
if (pet instance of Dog)
{
        ((Dog)pet).feedDog();
}
if (pet instance of Cat)
{
        ((Cat)pet).feedCat();
}

the main use of a map is to put similar things together.

地图的主要用途是将相似的东西放在一起。

if you want to really put different things then consider writing a new class.

如果您想真正放置不同的东西,请考虑编写一个新类。

回答by Thomas Jung

If everything else (polymorphic implementation, casts) is not applicable you can implement a heterogeneous containeras described in Item 33: Consider type-safe heterogeneous containersin "Effective Java", 3rd Edition. The responsibility of the container is to ensure type-safeness.

如果其他所有内容(多态实现、强制转换)都不适用,您可以实现一个异构容器,如第 33 项所述:考虑“有效 Java”,第 3 版中的类型安全异构容器。容器的职责是确保类型安全。

public class Container{
  private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
  public <T> void set(Class<T> klass, T thing) {
    favorites.put(klass, thing);
  }
  public <T> T get(Class<T> klass) {
    return klass.cast(favorites.get(klass));
  }
}

The problem with your example is that you're using a HashMap<K,V>as an entry type. This cannot be represented with a class literal as a type token. So you have to implement some form of super type token:

您的示例的问题在于您使用 aHashMap<K,V>作为条目类型。这不能用类文字表示为类型标记。所以你必须实现某种形式的超类型令牌

public abstract class TypeReference<T> {}

Your client code would then extend TypeReference for every type token needed:

然后,您的客户端代码将为所需的每个类型令牌扩展 TypeReference:

TypeReference<?> typeToken = new TypeReference<HashMap<String, Integer>>{};

The type information is accessible at run-time. The container implementation has then to type check against the actual type parameters ofof the type token (subclass of TypeReference).

类型信息可在运行时访问。然后容器实现必须针对类型标记(TypeReference 的子类)的实际类型参数进行类型检查。

This is a complete solution but a lot of work to implement. No collection library I know of does support containers with type references.

这是一个完整的解决方案,但要实现很多工作。据我所知,没有任何集合库支持带有类型引用的容器。