如何处理未检查的警告?

时间:2022-09-11 09:35:24

Eclipse is giving me a warning of the following form:

Eclipse给了我以下表单的警告:

Type safety: Unchecked cast from Object to HashMap

类型安全:不受限制地从对象转换到HashMap。

This is from a call to an API that I have no control over which returns Object:

这是来自对API的调用,我无法控制返回对象:

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
  HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
  return theHash;
}

I'd like to avoid Eclipse warnings, if possible, since theoretically they indicate at least a potential code problem. I haven't found a good way to eliminate this one yet, though. I can extract the single line involved out to a method by itself and add @SuppressWarnings("unchecked") to that method, thus limiting the impact of having a block of code where I ignore warnings. Any better options? I don't want to turn these warnings off in Eclipse.

如果可能的话,我希望避免使用Eclipse警告,因为理论上它们至少表明了潜在的代码问题。不过,我还没有找到消除这一问题的好办法。我可以将单独的一行代码提取到一个方法中,并将@抑制警告(“未选中的”)添加到该方法中,从而限制了我忽略警告的代码块的影响。有什么更好的选择吗?我不想在Eclipse中关闭这些警告。

Before I came to the code, it was simpler, but still provoked warnings:

在我来到代码之前,它更简单,但仍然引起了警告:

HashMap getItems(javax.servlet.http.HttpSession session) {
  HashMap theHash = (HashMap)session.getAttribute("attributeKey");
  return theHash;
}

Problem was elsewhere when you tried to use the hash you'd get warnings:

当你试图使用哈希时,问题就在别处:

HashMap items = getItems(session);
items.put("this", "that");

Type safety: The method put(Object, Object) belongs to the raw type HashMap.  References to generic type HashMap<K,V> should be parameterized.

24 个解决方案

#1


446  

The obvious answer, of course, is not to do the unchecked cast.

当然,最明显的答案是,不去做未经检查的演员。

If it's absolutely necessary, then at least try to limit the scope of the @SuppressWarnings annotation. According to its Javadocs, it can go on local variables; this way, it doesn't even affect the entire method.

如果这是绝对必要的,那么至少尝试限制@抑制警告注释的范围。根据它的Javadocs,它可以进行局部变量;这样,它甚至不会影响整个方法。

Example:

例子:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

There is no way to determine whether the Map really should have the generic parameters <String, String>. You must know beforehand what the parameters should be (or you'll find out when you get a ClassCastException). This is why the code generates a warning, because the compiler can't possibly know whether is safe.

没有办法确定地图是否真的应该有通用参数 。您必须预先知道参数应该是什么(或者您将在得到ClassCastException时发现)。这就是代码生成警告的原因,因为编译器不可能知道是否安全。 ,>

#2


113  

Unfortunately, there are no great options here. Remember, the goal of all of this is to preserve type safety. "Java Generics" offers a solutions for dealing with non-genericized legacy libraries, and there is one in particular called the "empty loop technique" in section section 8.2. Basically, make the unsafe cast, and suppress the warning. Then loop through the map like this:

不幸的是,这里没有很好的选择。记住,所有这些的目的是为了保护类型安全。“Java泛型”提供了处理非泛型的遗留库的解决方案,其中有一个在第8.2节中称为“空循环技术”。基本上,让不安全的演员,并压制警告。然后像这样在地图上循环:

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());

If an unexpected type is an encountered, you will get a runtime ClassCastException, but at least it will happen close to the source of the problem.

如果遇到意外类型,您将获得一个运行时ClassCastException,但至少它会发生在问题的源附近。

#3


109  

Wow; I think I figured out the answer to my own question. I'm just not sure it's worth it! :)

哇;我想我已经找到了我自己问题的答案。我只是不确定这是否值得!:)

The problem is the cast isn't checked. So, you have to check it yourself. You can't just check a parameterized type with instanceof, because the parameterized type information is unavailable at runtime, having been erased at compile time.

问题是演员没有被选中。所以,你必须自己检查一下。你不能仅仅用instanceof检查参数化类型,因为参数化类型信息在运行时不可用,在编译时被抹去。

But, you can perform a check on each and every item in the hash, with instanceof, and in doing so, you can construct a new hash that is type-safe. And you won't provoke any warnings.

但是,您可以对散列中的每一个项目执行一个检查,使用instanceof,并且这样做,您可以构造一个类型安全的新散列。而且你不会引起任何警告。

Thanks to mmyers and Esko Luontola, I've parameterized the code I originally wrote here, so it can be wrapped up in a utility class somewhere and used for any parameterized HashMap. If you want to understand it better and aren't very familiar with generics, I encourage viewing the edit history of this answer.

由于mmyers和Esko Luontola,我已经把我最初写在这里的代码参数化了,所以它可以被打包在一个实用程序类中,并用于任何参数化的HashMap。如果您想更好地理解它,并且不太熟悉泛型,我鼓励查看这个答案的编辑历史。

public static <K, V> HashMap<K, V> castHash(HashMap input,
                                            Class<K> keyClass,
                                            Class<V> valueClass) {
  HashMap<K, V> output = new HashMap<K, V>();
  if (input == null)
      return output;
  for (Object key: input.keySet().toArray()) {
    if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
        Object value = input.get(key);
        if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
            K k = keyClass.cast(key);
            V v = valueClass.cast(value);
            output.put(k, v);
        } else {
            throw new AssertionError(
                "Cannot cast to HashMap<"+ keyClass.getSimpleName()
                +", "+ valueClass.getSimpleName() +">"
                +", value "+ value +" is not a "+ valueClass.getSimpleName()
            );
        }
    } else {
        throw new AssertionError(
            "Cannot cast to HashMap<"+ keyClass.getSimpleName()
            +", "+ valueClass.getSimpleName() +">"
            +", key "+ key +" is not a " + keyClass.getSimpleName()
        );
    }
  }
  return output;
}

That's a lot of work, possibly for very little reward... I'm not sure if I'll use it or not. I'd appreciate any comments as to whether people think it's worth it or not. Also, I'd appreciate improvement suggestions: is there something better I can do besides throw AssertionErrors? Is there something better I could throw? Should I make it a checked Exception?

那是很多工作,可能很少报酬……我不确定我是否会用它。对于人们是否认为这是值得的,我很感激。同时,我也很欣赏改进建议:除了抛出AssertionErrors,还有什么更好的方法吗?有没有更好的东西我可以扔?我应该让它成为一个受控异常吗?

#4


47  

In Eclipse Preferences, Go to Java->Compiler->Errors/Warnings->Generic types and check the Ignore unavoidable generic type problems check-box.

在Eclipse首选项中,转到Java->编译器->错误/警告->泛型类型,并检查忽略不可避免的泛型类型问题复选框。

This satisfies the intent of the question, i.e.

这就满足了问题的意图,即

I'd like to avoid Eclipse warnings...

我想避免Eclipse警告……

if not the spirit.

如果没有精神。

#5


22  

You can create a utility class like the following, and use it to suppress the unchecked warning.

您可以像下面这样创建一个实用程序类,并使用它来抑制未检查的警告。

public class Objects {

    /**
     * Helps to avoid using {@code @SuppressWarnings({"unchecked"})} when casting to a generic type.
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }
}

You can use it as follows:

你可以使用以下方法:

import static Objects.uncheckedCast;
...

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
      return uncheckedCast(session.getAttribute("attributeKey"));
}

Some more discussion about this is here: http://cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html

这里有更多关于这个的讨论:http://cleveralias.blogs.com/t_spearmints/2006/01/swarning.html。

#6


18  

This stuff is hard, but here are my current thoughts:

这是很难的,但我现在的想法是:

If your API returns Object, then there's nothing you can do -- no matter what, you will be blindly casting the object. You let Java throw ClassCastExceptions, or you can check each element yourself and throw Assertions or IllegalArgumentExceptions or some such, but these runtime checks are all equivalent. You have to suppress the compile time unchecked cast no matter what you do at runtime.

如果您的API返回对象,那么您就无能为力了——无论如何,您将盲目地抛出对象。您让Java抛出classcastexception,或者您可以自己检查每个元素,并抛出断言或illegalargumentexception或一些此类,但是这些运行时检查都是等价的。无论您在运行时做什么,您都必须抑制编译时未选中的内容。

I'd just prefer to blind cast and let the JVM perform its runtime check for me since we "know" what the API should return, and are usually willing to assume that the API works. Use generics everywhere above the cast, if you need them. You aren't really buying anything there since you still have the single blind cast, but at least you can use generics from there on up so the JVM can help you avoid blind casts in other pieces of your code.

我只是更喜欢盲目的cast,让JVM执行它的运行时检查,因为我们“知道”API应该返回什么,并且通常愿意假定API是有效的。如果你需要的话,可以在任何地方使用泛型。您并没有在那里购买任何东西,因为您仍然拥有单个的盲cast,但是至少您可以在上面使用泛型,这样JVM可以帮助您避免在代码的其他部分中进行盲目的转换。

In this particular case, presumably you can see the call to SetAttribute and see the type is going in, so just blind-casting the type to same on the way out is not immoral. Add a comment referencing the SetAttribute and be done with it.

在这个特定的例子中,假设您可以看到SetAttribute的调用,并且看到类型正在进入,所以在退出的方式上,将类型设置为相同的,并不是不道德的。添加一个引用SetAttribute的注释并完成它。

#7


11  

In the HTTP Session world you can't really avoid the cast, since the API is written that way (takes and returns only Object).

在HTTP会话世界中,您不能真正避免cast,因为API是这样编写的(只返回对象)。

With a little bit of work you can easily avoid the unchecked cast, 'though. This means that it will turn into a traditional cast giving a ClassCastException right there in the event of an error). An unchecked exception could turn into a CCE at any point later on instead of the point of the cast (that's the reason why it's a separate warning).

只要有一点点的工作,你就可以轻松地避开不受约束的演员。这意味着它将变成一个传统的cast,在发生错误的时候提供ClassCastException。未经检查的异常可能会在以后的任何时候变成CCE,而不是cast(这就是为什么它是一个单独的警告)。

Replace the HashMap with a dedicated class:

将HashMap替换为专用类:

import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Attributes extends AbstractMap<String, String> {
    final Map<String, String> content = new HashMap<String, String>();

    @Override
    public Set<Map.Entry<String, String>> entrySet() {
        return content.entrySet();
    }

    @Override
    public Set<String> keySet() {
        return content.keySet();
    }

    @Override
    public Collection<String> values() {
        return content.values();
    }

    @Override
    public String put(final String key, final String value) {
        return content.put(key, value);
    }
}

Then cast to that class instead of Map<String,String> and everything will be checked at the exact place where you write your code. No unexpected ClassCastExceptions later on.

然后转换到那个类而不是Map ,所有的东西都将在您编写代码的确切位置进行检查。以后不会出现意外的classcastexception异常。 ,string>

#8


8  

In this particular case, I would not store Maps into the HttpSession directly, but instead an instance of my own class, which in turn contains a Map (an implementation detail of the class). Then you can be sure that the elements in the map are of the right type.

在这个特殊的例子中,我不会直接将映射存储到HttpSession中,而是将它作为我自己类的一个实例,而这个类又包含一个映射(类的实现细节)。然后您可以确定map中的元素是正确的类型。

But if you anyways want to check that the contents of the Map are of right type, you could use a code like this:

但是如果你想检查地图的内容是否正确,你可以使用这样的代码:

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("a", 1);
    map.put("b", 2);
    Object obj = map;

    Map<String, Integer> ok = safeCastMap(obj, String.class, Integer.class);
    Map<String, String> error = safeCastMap(obj, String.class, String.class);
}

@SuppressWarnings({"unchecked"})
public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType, Class<V> valueType) {
    checkMap(map);
    checkMapContents(keyType, valueType, (Map<?, ?>) map);
    return (Map<K, V>) map;
}

private static void checkMap(Object map) {
    checkType(Map.class, map);
}

private static <K, V> void checkMapContents(Class<K> keyType, Class<V> valueType, Map<?, ?> map) {
    for (Map.Entry<?, ?> entry : map.entrySet()) {
        checkType(keyType, entry.getKey());
        checkType(valueType, entry.getValue());
    }
}

private static <K> void checkType(Class<K> expectedType, Object obj) {
    if (!expectedType.isInstance(obj)) {
        throw new IllegalArgumentException("Expected " + expectedType + " but was " + obj.getClass() + ": " + obj);
    }
}

#9


6  

Here is a shortened example that avoids the "unchecked cast" warning by employing two strategies mentioned in other answers.

这里有一个缩短的例子,通过使用其他答案中提到的两种策略来避免“未选中的cast”警告。

  1. Pass down the Class of the type of interest as a parameter at runtime (Class<T> inputElementClazz). Then you can use: inputElementClazz.cast(anyObject);

    在运行时将感兴趣的类型作为参数传递(类 inputElementClazz)。然后你可以使用:inputElementClazz.cast(anyObject);

  2. For type casting of a Collection, use the wildcard ? instead of a generic type T to acknowledge that you indeed do not know what kind of objects to expect from the legacy code (Collection<?> unknownTypeCollection). After all, this is what the "unchecked cast" warning wants to tell us: We cannot be sure that we get a Collection<T>, so the honest thing to do is to use a Collection<?>. If absolutely needed, a collection of a known type can still be built (Collection<T> knownTypeCollection).

    对于集合的类型转换,使用通配符?不要使用泛型类型T来确认您确实不知道要从遗留代码中期望什么类型的对象(集合 unknownTypeCollection)。毕竟,这是“未检查的cast”警告想要告诉我们的:我们不能确定我们是否得到了一个集合 ,所以诚实的做法是使用集合 。如果绝对需要,还可以构建一个已知类型的集合(集合 knownTypeCollection)。

The legacy code interfaced in the example below has an attribute "input" in the StructuredViewer (StructuredViewer is a tree or table widget, "input" is the data model behind it). This "input" could be any kind of Java Collection.

在下面的例子中,遗留代码在结构查看器中有一个属性“input”(StructuredViewer是树或表小部件,“input”是它后面的数据模型)。这个“输入”可以是任何类型的Java集合。

public void dragFinished(StructuredViewer structuredViewer, Class<T> inputElementClazz) {
    IStructuredSelection selection = (IStructuredSelection) structuredViewer.getSelection();
    // legacy code returns an Object from getFirstElement,
    // the developer knows/hopes it is of type inputElementClazz, but the compiler cannot know
    T firstElement = inputElementClazz.cast(selection.getFirstElement());

    // legacy code returns an object from getInput, so we deal with it as a Collection<?>
    Collection<?> unknownTypeCollection = (Collection<?>) structuredViewer.getInput();

    // for some operations we do not even need a collection with known types
    unknownTypeCollection.remove(firstElement);

    // nothing prevents us from building a Collection of a known type, should we really need one
    Collection<T> knownTypeCollection = new ArrayList<T>();
    for (Object object : unknownTypeCollection) {
        T aT = inputElementClazz.cast(object);
        knownTypeCollection.add(aT);
        System.out.println(aT.getClass());
    }

    structuredViewer.refresh();
}

Naturally, the code above can give runtime errors if we use the legacy code with the wrong data types (e.g. if we set an array as the "input" of the StructuredViewer instead of a Java Collection).

当然,如果我们使用错误数据类型的遗留代码(例如,如果我们将数组设置为结构化查看器的“输入”而不是Java集合),那么上面的代码就会给出运行时错误。

Example of calling the method:

调用方法的示例:

dragFinishedStrategy.dragFinished(viewer, Product.class);

#10


4  

Warning suppression is not a solution. You should not be doing two level casting in one statement.

警告抑制不是一个解决方案。您不应该在一个语句中执行两个级别的转换。

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {

    // first, cast the returned Object to generic HashMap<?,?>
    HashMap<?, ?> theHash = (HashMap<?, ?>)session.getAttribute("attributeKey");

    // next, cast every entry of the HashMap to the required type <String, String>
    HashMap<String, String> returingHash = new HashMap<>();
    for (Entry<?, ?> entry : theHash.entrySet()) {
        returingHash.put((String) entry.getKey(), (String) entry.getValue());
    }
    return returingHash;
}

#11


4  

The Objects.Unchecked utility function in the answer above by Esko Luontola is a great way to avoid program clutter.

的对象。Esko Luontola在上面的答案中不加检查的效用函数是避免程序混乱的好方法。

If you don't want the SuppressWarnings on an entire method, Java forces you to put it on a local. If you need a cast on a member it can lead to code like this:

如果您不想在整个方法上使用抑制警告,那么Java将强制您将其放在本地。如果您需要一个成员,它可以导致这样的代码:

@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;

Using the utility is much cleaner, and it's still obvious what you are doing:

使用这个工具会更干净,而且很明显你在做什么:

this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());

NOTE: I feel its important to add that sometimes the warning really means you are doing something wrong like :

注意:我觉得很重要的一点是,有时候这个警告真的意味着你在做一些错误的事情:

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
Object intListObject = intList; 

 // this line gives an unchecked warning - but no runtime error
ArrayList<String> stringList  = (ArrayList<String>) intListObject;
System.out.println(stringList.get(0)); // cast exception will be given here

What the compiler is telling you is that this cast will NOT be checked at runtime, so no runtime error will be raised until you try to access the data in the generic container.

编译器告诉您的是,在运行时不会检查该转换,因此在尝试访问泛型容器中的数据之前不会提高运行时错误。

#12


3  

In Android Studio if you want to disable inspection you can use:

在安卓工作室,如果你想禁用检查,你可以使用:

//noinspection unchecked
Map<String, String> myMap = (Map<String, String>) deserializeMap();

#13


2  

A quick guess if you post your code can say for sure but you might have done something along the lines of

一个快速的猜测,如果你发布你的代码可以肯定,但是你可能已经做了一些类似的事情。

HashMap<String, Object> test = new HashMap();

which will produce the warning when you need to do

当你需要做的时候,哪个会发出警告?

HashMap<String, Object> test = new HashMap<String, Object>();

it might be worth looking at

这可能值得一看。

Generics in the Java Programming Language

Java编程语言中的泛型。

if your unfamiliar with what needs to be done.

如果你不熟悉需要做的事情。

#14


2  

I may have misunderstood the question(an example and a couple of surrounding lines would be nice), but why don't you always use an appropriate interface (and Java5+)? I see no reason why you would ever want to cast to a HashMap instead of a Map<KeyType,ValueType>. In fact, I can't imagine any reason to set the type of a variable to HashMap instead of Map.

我可能误解了这个问题(一个示例和一些周围的行是不错的),但是为什么不总是使用适当的接口(和Java5+)呢?我看不出您为什么想要转换到HashMap而不是Map 。事实上,我无法想象将变量类型设置为HashMap而不是Map的任何理由。 ,valuetype>

And why is the source an Object? Is it a parameter type of a legacy collection? If so, use generics and specify the type you want.

为什么源是一个对象?它是遗留集合的参数类型吗?如果是,请使用泛型并指定您想要的类型。

#15


2  

If I have to use an API that doesn't support Generics.. I try and isolate those calls in wrapper routines with as few lines as possible. I then use the SuppressWarnings annotation and also add the type-safety casts at the same time.

如果我必须使用不支持泛型的API。我尝试用尽可能少的行来隔离那些调用。然后,我使用抑制警告注释,并同时添加类型安全类型的转换。

This is just a personal preference to keep things as neat as possible.

这只是个人喜好,尽量保持整洁。

#16


2  

Take this one, it's much faster than creating a new HashMap, if it's already one, but still secure, as each element is checked against it's type...

以这个为例,它比创建一个新的HashMap要快得多,如果它已经是一个HashMap,但是仍然是安全的,因为每个元素都被检查为类型……

@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> toHashMap(Object input, Class<K> key, Class<V> value) {
       assert input instanceof Map : input;

       for (Map.Entry<?, ?> e : ((HashMap<?, ?>) input).entrySet()) {
           assert key.isAssignableFrom(e.getKey().getClass()) : "Map contains invalid keys";
           assert value.isAssignableFrom(e.getValue().getClass()) : "Map contains invalid values";
       }

       if (input instanceof HashMap)
           return (HashMap<K, V>) input;
       return new HashMap<K, V>((Map<K, V>) input);
    }

#17


1  

Just typecheck it before you cast it.

在你投下之前先用打字机打一下。

Object someObject = session.getAttribute("attributeKey");
if(someObject instanceof HashMap)
HashMap<String, String> theHash = (HashMap<String, String>)someObject;  

And for anyone asking, it's quite common to receive objects where you aren't sure of the type. Plenty of legacy "SOA" implementations pass around various objects that you shouldn't always trust. (The horrors!)

对于任何人来说,在不确定类型的情况下接收对象是很常见的。大量遗留的“SOA”实现传递了您不应该始终信任的各种对象。(恐怖!)

EDIT Changed the example code once to match the poster's updates, and following some comments I see that instanceof doesn't play nicely with generics. However changing the check to validate the outer object seems to play well with the commandline compiler. Revised example now posted.

编辑修改了示例代码,以匹配poster的更新,并遵循一些注释,我看到instanceof不适合泛型。但是,更改检查以验证外部对象似乎与commandline编译器很好。现在发布修改后的示例。

#18


1  

Almost every problem in Computer Science can be solved by adding a level of indirection*, or something.

计算机科学中几乎所有的问题都可以通过增加一个间接的程度来解决。

So introduce a non-generic object that is of a higher-level that a Map. With no context it isn't going to look very convincing, but anyway:

因此,引入一个非通用对象,它是一个更高级别的映射。没有上下文,它看起来不会很有说服力,但无论如何:

public final class Items implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String,String> map;
    public Items(Map<String,String> map) {
        this.map = New.immutableMap(map);
    }
    public Map<String,String> getMap() {
        return map;
    }
    @Override public String toString() {
        return map.toString();
    }
}

public final class New {
    public static <K,V> Map<K,V> immutableMap(
        Map<? extends K, ? extends V> original
    ) {
        // ... optimise as you wish...
        return Collections.unmodifiableMap(
            new HashMap<String,String>(original)
        );
    }
}

static Map<String, String> getItems(HttpSession session) {
    Items items = (Items)
        session.getAttribute("attributeKey");
    return items.getMap();
}

*Except too many levels of indirection.

*除了太多的间接方向。

#19


1  

Here's one way I handle this when I override the equals() operation.

当我重写equals()操作时,这里有一种处理方法。

public abstract class Section<T extends Section> extends Element<Section<T>> {
    Object attr1;

    /**
    * Compare one section object to another.
    *
    * @param obj the object being compared with this section object
    * @return true if this section and the other section are of the same
    * sub-class of section and their component fields are the same, false
    * otherwise
    */       
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            // this exists, but obj doesn't, so they can't be equal!
            return false;
        }

        // prepare to cast...
        Section<?> other;

        if (getClass() != obj.getClass()) {
            // looks like we're comparing apples to oranges
            return false;
        } else {
            // it must be safe to make that cast!
            other = (Section<?>) obj;
        }

        // and then I compare attributes between this and other
        return this.attr1.equals(other.attr1);
    }
}

This seems to work in Java 8 (even compiled with -Xlint:unchecked)

这似乎适用于Java 8(甚至用-Xlint编译)

#20


0  

The problem lies in here:

问题在于:

... = (HashMap<String, String>)session.getAttribute("attributeKey");

The result of session.getAttribute(...) is an object which could be anything, but since you "know" it's a HashMap<String, String> you're just casting without checking it first. Thus, the warning. To be pedantic, which Java wants you to be in this case, you should retrieve the result and verify it's compatibility with instanceof.

getattribute(…)的结果是一个可以是任何东西的对象,但是由于您“知道”它是一个HashMap ,您只是在不检查它的情况下进行转换。因此,警告。要成为pedantic, Java希望您在这种情况下,您应该检索结果并验证它与instanceof的兼容性。 ,>

#21


0  

If you are sure that the type returned by session.getAttribute() is HashMap then you can not typecast to that exact type, but rely on only checking the generic HashMap

如果您确定session.getAttribute()返回的类型是HashMap,那么您就不能对该类型进行类型转换,而是只依赖于检查通用的HashMap。

HashMap<?,?> getItems(javax.servlet.http.HttpSession session) {  
    HashMap<?,?> theHash = (HashMap<?,?>)session.getAttribute("attributeKey");
    return theHash;
} 

Eclipse will then surprise warnings, but of course this can lead to runtime errors that can be hard to debug. I use this approach in not operation-critical contexts only.

Eclipse会突然发出警告,但是这当然会导致运行时的错误,而这些错误很难调试。我只使用这种方法,而不是在操作关键的上下文中。

#22


0  

Two ways, one which avoids the tag completely, the other using a naughty but nice utility method.
The problem is pre-genericised Collections...
I believe the rule of thumb is: "cast objects one thing at a time" - what this means when trying to use raw classes in a genericised world is that because you don't know what is in this Map<?, ?> (and indeed the JVM might even find that it isn't even a Map!), it obvious when you think about it that you can't cast it. If you had a Map<String, ?> map2 then HashSet<String> keys = (HashSet<String>)map2.keySet() does not give you a warning, despite this being an "act of faith" for the compiler (because it might turn out to be a TreeSet)... but it is only a single act of faith.

PS to the objection that iterating as in my first way "is boring" and "takes time", the answer is "no pain no gain": a genericised collection is guaranteed to contain Map.Entry<String, String>s, and nothing else. You have to pay for this guarantee. When using generics systematically this payment, beautifully, takes the form of coding compliance, not machine time!
One school of thought might say that you should set Eclipse's settings to make such unchecked casts errors, rather than warnings. In that case you would have to use my first way.

有两种方法,一种是完全避免使用标签,另一种是使用一种很好的实用方法。这个问题是预生成的集合……我相信经验法则是:“一次抛一件东西”——这意味着当你试图在一个普遍的世界里使用原始的类时,因为你不知道这幅地图里有什么?>(实际上JVM甚至可能会发现它甚至不是一张地图!),当你想它时,它就很明显了。如果您有一个Map map2然后HashSet keys = (HashSet )map2. keyset()不会给您一个警告,尽管这是编译器的“信任行为”(因为它可能是一个TreeSet)……但这只是一种信念。在我的第一种方式“无聊”和“需要时间”的反对意见中,答案是“没有痛苦没有收获”:一个通用的集合被保证包含地图。输入 s,其他都没有。你必须付这个保修费。当系统地使用泛型时,很好地采用了编码遵从性的形式,而不是机器时间!一种思想流派可能会说,您应该设置Eclipse的设置,使其不受检查地抛出错误,而不是警告。在那种情况下,你必须用我的第一种方法。 ,> ,>

package scratchpad;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

public class YellowMouse {

    // First way

    Map<String, String> getHashMapStudiouslyAvoidingSuppressTag(HttpSession session) {
      Map<?, ?> theHash = (Map<?, ?>)session.getAttribute("attributeKey");

      Map<String, String> yellowMouse = new HashMap<String, String>();
      for( Map.Entry<?, ?> entry : theHash.entrySet() ){
        yellowMouse.put( (String)entry.getKey(), (String)entry.getValue() );
      }

      return yellowMouse;
    }


    // Second way

    Map<String, String> getHashMapUsingNaughtyButNiceUtilityMethod(HttpSession session) {
      return uncheckedCast( session.getAttribute("attributeKey") );
    }


    // NB this is a utility method which should be kept in your utility library. If you do that it will
    // be the *only* time in your entire life that you will have to use this particular tag!!

    @SuppressWarnings({ "unchecked" })
    public static synchronized <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }


}

#23


-1  

This makes the warnings go away...

这使得警告消失了……

 static Map<String, String> getItems(HttpSession session) {
        HashMap<?, ?> theHash1 = (HashMap<String,String>)session.getAttribute("attributeKey");
        HashMap<String,String> theHash = (HashMap<String,String>)theHash1;
    return theHash;
}

#24


-3  

Solution: Disable this warning in Eclipse. Don't @SuppressWarnings it, just disable it completely.

解决方案:在Eclipse中禁用此警告。不要警告它,只要完全禁用它。

Several of the "solutions" presented above are way out of line, making code unreadable for the sake of suppressing a silly warning.

上面提出的几个“解决方案”都是不正常的,为了抑制一个愚蠢的警告,使得代码变得不可读。

#1


446  

The obvious answer, of course, is not to do the unchecked cast.

当然,最明显的答案是,不去做未经检查的演员。

If it's absolutely necessary, then at least try to limit the scope of the @SuppressWarnings annotation. According to its Javadocs, it can go on local variables; this way, it doesn't even affect the entire method.

如果这是绝对必要的,那么至少尝试限制@抑制警告注释的范围。根据它的Javadocs,它可以进行局部变量;这样,它甚至不会影响整个方法。

Example:

例子:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

There is no way to determine whether the Map really should have the generic parameters <String, String>. You must know beforehand what the parameters should be (or you'll find out when you get a ClassCastException). This is why the code generates a warning, because the compiler can't possibly know whether is safe.

没有办法确定地图是否真的应该有通用参数 。您必须预先知道参数应该是什么(或者您将在得到ClassCastException时发现)。这就是代码生成警告的原因,因为编译器不可能知道是否安全。 ,>

#2


113  

Unfortunately, there are no great options here. Remember, the goal of all of this is to preserve type safety. "Java Generics" offers a solutions for dealing with non-genericized legacy libraries, and there is one in particular called the "empty loop technique" in section section 8.2. Basically, make the unsafe cast, and suppress the warning. Then loop through the map like this:

不幸的是,这里没有很好的选择。记住,所有这些的目的是为了保护类型安全。“Java泛型”提供了处理非泛型的遗留库的解决方案,其中有一个在第8.2节中称为“空循环技术”。基本上,让不安全的演员,并压制警告。然后像这样在地图上循环:

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());

If an unexpected type is an encountered, you will get a runtime ClassCastException, but at least it will happen close to the source of the problem.

如果遇到意外类型,您将获得一个运行时ClassCastException,但至少它会发生在问题的源附近。

#3


109  

Wow; I think I figured out the answer to my own question. I'm just not sure it's worth it! :)

哇;我想我已经找到了我自己问题的答案。我只是不确定这是否值得!:)

The problem is the cast isn't checked. So, you have to check it yourself. You can't just check a parameterized type with instanceof, because the parameterized type information is unavailable at runtime, having been erased at compile time.

问题是演员没有被选中。所以,你必须自己检查一下。你不能仅仅用instanceof检查参数化类型,因为参数化类型信息在运行时不可用,在编译时被抹去。

But, you can perform a check on each and every item in the hash, with instanceof, and in doing so, you can construct a new hash that is type-safe. And you won't provoke any warnings.

但是,您可以对散列中的每一个项目执行一个检查,使用instanceof,并且这样做,您可以构造一个类型安全的新散列。而且你不会引起任何警告。

Thanks to mmyers and Esko Luontola, I've parameterized the code I originally wrote here, so it can be wrapped up in a utility class somewhere and used for any parameterized HashMap. If you want to understand it better and aren't very familiar with generics, I encourage viewing the edit history of this answer.

由于mmyers和Esko Luontola,我已经把我最初写在这里的代码参数化了,所以它可以被打包在一个实用程序类中,并用于任何参数化的HashMap。如果您想更好地理解它,并且不太熟悉泛型,我鼓励查看这个答案的编辑历史。

public static <K, V> HashMap<K, V> castHash(HashMap input,
                                            Class<K> keyClass,
                                            Class<V> valueClass) {
  HashMap<K, V> output = new HashMap<K, V>();
  if (input == null)
      return output;
  for (Object key: input.keySet().toArray()) {
    if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
        Object value = input.get(key);
        if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
            K k = keyClass.cast(key);
            V v = valueClass.cast(value);
            output.put(k, v);
        } else {
            throw new AssertionError(
                "Cannot cast to HashMap<"+ keyClass.getSimpleName()
                +", "+ valueClass.getSimpleName() +">"
                +", value "+ value +" is not a "+ valueClass.getSimpleName()
            );
        }
    } else {
        throw new AssertionError(
            "Cannot cast to HashMap<"+ keyClass.getSimpleName()
            +", "+ valueClass.getSimpleName() +">"
            +", key "+ key +" is not a " + keyClass.getSimpleName()
        );
    }
  }
  return output;
}

That's a lot of work, possibly for very little reward... I'm not sure if I'll use it or not. I'd appreciate any comments as to whether people think it's worth it or not. Also, I'd appreciate improvement suggestions: is there something better I can do besides throw AssertionErrors? Is there something better I could throw? Should I make it a checked Exception?

那是很多工作,可能很少报酬……我不确定我是否会用它。对于人们是否认为这是值得的,我很感激。同时,我也很欣赏改进建议:除了抛出AssertionErrors,还有什么更好的方法吗?有没有更好的东西我可以扔?我应该让它成为一个受控异常吗?

#4


47  

In Eclipse Preferences, Go to Java->Compiler->Errors/Warnings->Generic types and check the Ignore unavoidable generic type problems check-box.

在Eclipse首选项中,转到Java->编译器->错误/警告->泛型类型,并检查忽略不可避免的泛型类型问题复选框。

This satisfies the intent of the question, i.e.

这就满足了问题的意图,即

I'd like to avoid Eclipse warnings...

我想避免Eclipse警告……

if not the spirit.

如果没有精神。

#5


22  

You can create a utility class like the following, and use it to suppress the unchecked warning.

您可以像下面这样创建一个实用程序类,并使用它来抑制未检查的警告。

public class Objects {

    /**
     * Helps to avoid using {@code @SuppressWarnings({"unchecked"})} when casting to a generic type.
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }
}

You can use it as follows:

你可以使用以下方法:

import static Objects.uncheckedCast;
...

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
      return uncheckedCast(session.getAttribute("attributeKey"));
}

Some more discussion about this is here: http://cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html

这里有更多关于这个的讨论:http://cleveralias.blogs.com/t_spearmints/2006/01/swarning.html。

#6


18  

This stuff is hard, but here are my current thoughts:

这是很难的,但我现在的想法是:

If your API returns Object, then there's nothing you can do -- no matter what, you will be blindly casting the object. You let Java throw ClassCastExceptions, or you can check each element yourself and throw Assertions or IllegalArgumentExceptions or some such, but these runtime checks are all equivalent. You have to suppress the compile time unchecked cast no matter what you do at runtime.

如果您的API返回对象,那么您就无能为力了——无论如何,您将盲目地抛出对象。您让Java抛出classcastexception,或者您可以自己检查每个元素,并抛出断言或illegalargumentexception或一些此类,但是这些运行时检查都是等价的。无论您在运行时做什么,您都必须抑制编译时未选中的内容。

I'd just prefer to blind cast and let the JVM perform its runtime check for me since we "know" what the API should return, and are usually willing to assume that the API works. Use generics everywhere above the cast, if you need them. You aren't really buying anything there since you still have the single blind cast, but at least you can use generics from there on up so the JVM can help you avoid blind casts in other pieces of your code.

我只是更喜欢盲目的cast,让JVM执行它的运行时检查,因为我们“知道”API应该返回什么,并且通常愿意假定API是有效的。如果你需要的话,可以在任何地方使用泛型。您并没有在那里购买任何东西,因为您仍然拥有单个的盲cast,但是至少您可以在上面使用泛型,这样JVM可以帮助您避免在代码的其他部分中进行盲目的转换。

In this particular case, presumably you can see the call to SetAttribute and see the type is going in, so just blind-casting the type to same on the way out is not immoral. Add a comment referencing the SetAttribute and be done with it.

在这个特定的例子中,假设您可以看到SetAttribute的调用,并且看到类型正在进入,所以在退出的方式上,将类型设置为相同的,并不是不道德的。添加一个引用SetAttribute的注释并完成它。

#7


11  

In the HTTP Session world you can't really avoid the cast, since the API is written that way (takes and returns only Object).

在HTTP会话世界中,您不能真正避免cast,因为API是这样编写的(只返回对象)。

With a little bit of work you can easily avoid the unchecked cast, 'though. This means that it will turn into a traditional cast giving a ClassCastException right there in the event of an error). An unchecked exception could turn into a CCE at any point later on instead of the point of the cast (that's the reason why it's a separate warning).

只要有一点点的工作,你就可以轻松地避开不受约束的演员。这意味着它将变成一个传统的cast,在发生错误的时候提供ClassCastException。未经检查的异常可能会在以后的任何时候变成CCE,而不是cast(这就是为什么它是一个单独的警告)。

Replace the HashMap with a dedicated class:

将HashMap替换为专用类:

import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Attributes extends AbstractMap<String, String> {
    final Map<String, String> content = new HashMap<String, String>();

    @Override
    public Set<Map.Entry<String, String>> entrySet() {
        return content.entrySet();
    }

    @Override
    public Set<String> keySet() {
        return content.keySet();
    }

    @Override
    public Collection<String> values() {
        return content.values();
    }

    @Override
    public String put(final String key, final String value) {
        return content.put(key, value);
    }
}

Then cast to that class instead of Map<String,String> and everything will be checked at the exact place where you write your code. No unexpected ClassCastExceptions later on.

然后转换到那个类而不是Map ,所有的东西都将在您编写代码的确切位置进行检查。以后不会出现意外的classcastexception异常。 ,string>

#8


8  

In this particular case, I would not store Maps into the HttpSession directly, but instead an instance of my own class, which in turn contains a Map (an implementation detail of the class). Then you can be sure that the elements in the map are of the right type.

在这个特殊的例子中,我不会直接将映射存储到HttpSession中,而是将它作为我自己类的一个实例,而这个类又包含一个映射(类的实现细节)。然后您可以确定map中的元素是正确的类型。

But if you anyways want to check that the contents of the Map are of right type, you could use a code like this:

但是如果你想检查地图的内容是否正确,你可以使用这样的代码:

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("a", 1);
    map.put("b", 2);
    Object obj = map;

    Map<String, Integer> ok = safeCastMap(obj, String.class, Integer.class);
    Map<String, String> error = safeCastMap(obj, String.class, String.class);
}

@SuppressWarnings({"unchecked"})
public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType, Class<V> valueType) {
    checkMap(map);
    checkMapContents(keyType, valueType, (Map<?, ?>) map);
    return (Map<K, V>) map;
}

private static void checkMap(Object map) {
    checkType(Map.class, map);
}

private static <K, V> void checkMapContents(Class<K> keyType, Class<V> valueType, Map<?, ?> map) {
    for (Map.Entry<?, ?> entry : map.entrySet()) {
        checkType(keyType, entry.getKey());
        checkType(valueType, entry.getValue());
    }
}

private static <K> void checkType(Class<K> expectedType, Object obj) {
    if (!expectedType.isInstance(obj)) {
        throw new IllegalArgumentException("Expected " + expectedType + " but was " + obj.getClass() + ": " + obj);
    }
}

#9


6  

Here is a shortened example that avoids the "unchecked cast" warning by employing two strategies mentioned in other answers.

这里有一个缩短的例子,通过使用其他答案中提到的两种策略来避免“未选中的cast”警告。

  1. Pass down the Class of the type of interest as a parameter at runtime (Class<T> inputElementClazz). Then you can use: inputElementClazz.cast(anyObject);

    在运行时将感兴趣的类型作为参数传递(类 inputElementClazz)。然后你可以使用:inputElementClazz.cast(anyObject);

  2. For type casting of a Collection, use the wildcard ? instead of a generic type T to acknowledge that you indeed do not know what kind of objects to expect from the legacy code (Collection<?> unknownTypeCollection). After all, this is what the "unchecked cast" warning wants to tell us: We cannot be sure that we get a Collection<T>, so the honest thing to do is to use a Collection<?>. If absolutely needed, a collection of a known type can still be built (Collection<T> knownTypeCollection).

    对于集合的类型转换,使用通配符?不要使用泛型类型T来确认您确实不知道要从遗留代码中期望什么类型的对象(集合 unknownTypeCollection)。毕竟,这是“未检查的cast”警告想要告诉我们的:我们不能确定我们是否得到了一个集合 ,所以诚实的做法是使用集合 。如果绝对需要,还可以构建一个已知类型的集合(集合 knownTypeCollection)。

The legacy code interfaced in the example below has an attribute "input" in the StructuredViewer (StructuredViewer is a tree or table widget, "input" is the data model behind it). This "input" could be any kind of Java Collection.

在下面的例子中,遗留代码在结构查看器中有一个属性“input”(StructuredViewer是树或表小部件,“input”是它后面的数据模型)。这个“输入”可以是任何类型的Java集合。

public void dragFinished(StructuredViewer structuredViewer, Class<T> inputElementClazz) {
    IStructuredSelection selection = (IStructuredSelection) structuredViewer.getSelection();
    // legacy code returns an Object from getFirstElement,
    // the developer knows/hopes it is of type inputElementClazz, but the compiler cannot know
    T firstElement = inputElementClazz.cast(selection.getFirstElement());

    // legacy code returns an object from getInput, so we deal with it as a Collection<?>
    Collection<?> unknownTypeCollection = (Collection<?>) structuredViewer.getInput();

    // for some operations we do not even need a collection with known types
    unknownTypeCollection.remove(firstElement);

    // nothing prevents us from building a Collection of a known type, should we really need one
    Collection<T> knownTypeCollection = new ArrayList<T>();
    for (Object object : unknownTypeCollection) {
        T aT = inputElementClazz.cast(object);
        knownTypeCollection.add(aT);
        System.out.println(aT.getClass());
    }

    structuredViewer.refresh();
}

Naturally, the code above can give runtime errors if we use the legacy code with the wrong data types (e.g. if we set an array as the "input" of the StructuredViewer instead of a Java Collection).

当然,如果我们使用错误数据类型的遗留代码(例如,如果我们将数组设置为结构化查看器的“输入”而不是Java集合),那么上面的代码就会给出运行时错误。

Example of calling the method:

调用方法的示例:

dragFinishedStrategy.dragFinished(viewer, Product.class);

#10


4  

Warning suppression is not a solution. You should not be doing two level casting in one statement.

警告抑制不是一个解决方案。您不应该在一个语句中执行两个级别的转换。

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {

    // first, cast the returned Object to generic HashMap<?,?>
    HashMap<?, ?> theHash = (HashMap<?, ?>)session.getAttribute("attributeKey");

    // next, cast every entry of the HashMap to the required type <String, String>
    HashMap<String, String> returingHash = new HashMap<>();
    for (Entry<?, ?> entry : theHash.entrySet()) {
        returingHash.put((String) entry.getKey(), (String) entry.getValue());
    }
    return returingHash;
}

#11


4  

The Objects.Unchecked utility function in the answer above by Esko Luontola is a great way to avoid program clutter.

的对象。Esko Luontola在上面的答案中不加检查的效用函数是避免程序混乱的好方法。

If you don't want the SuppressWarnings on an entire method, Java forces you to put it on a local. If you need a cast on a member it can lead to code like this:

如果您不想在整个方法上使用抑制警告,那么Java将强制您将其放在本地。如果您需要一个成员,它可以导致这样的代码:

@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;

Using the utility is much cleaner, and it's still obvious what you are doing:

使用这个工具会更干净,而且很明显你在做什么:

this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());

NOTE: I feel its important to add that sometimes the warning really means you are doing something wrong like :

注意:我觉得很重要的一点是,有时候这个警告真的意味着你在做一些错误的事情:

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
Object intListObject = intList; 

 // this line gives an unchecked warning - but no runtime error
ArrayList<String> stringList  = (ArrayList<String>) intListObject;
System.out.println(stringList.get(0)); // cast exception will be given here

What the compiler is telling you is that this cast will NOT be checked at runtime, so no runtime error will be raised until you try to access the data in the generic container.

编译器告诉您的是,在运行时不会检查该转换,因此在尝试访问泛型容器中的数据之前不会提高运行时错误。

#12


3  

In Android Studio if you want to disable inspection you can use:

在安卓工作室,如果你想禁用检查,你可以使用:

//noinspection unchecked
Map<String, String> myMap = (Map<String, String>) deserializeMap();

#13


2  

A quick guess if you post your code can say for sure but you might have done something along the lines of

一个快速的猜测,如果你发布你的代码可以肯定,但是你可能已经做了一些类似的事情。

HashMap<String, Object> test = new HashMap();

which will produce the warning when you need to do

当你需要做的时候,哪个会发出警告?

HashMap<String, Object> test = new HashMap<String, Object>();

it might be worth looking at

这可能值得一看。

Generics in the Java Programming Language

Java编程语言中的泛型。

if your unfamiliar with what needs to be done.

如果你不熟悉需要做的事情。

#14


2  

I may have misunderstood the question(an example and a couple of surrounding lines would be nice), but why don't you always use an appropriate interface (and Java5+)? I see no reason why you would ever want to cast to a HashMap instead of a Map<KeyType,ValueType>. In fact, I can't imagine any reason to set the type of a variable to HashMap instead of Map.

我可能误解了这个问题(一个示例和一些周围的行是不错的),但是为什么不总是使用适当的接口(和Java5+)呢?我看不出您为什么想要转换到HashMap而不是Map 。事实上,我无法想象将变量类型设置为HashMap而不是Map的任何理由。 ,valuetype>

And why is the source an Object? Is it a parameter type of a legacy collection? If so, use generics and specify the type you want.

为什么源是一个对象?它是遗留集合的参数类型吗?如果是,请使用泛型并指定您想要的类型。

#15


2  

If I have to use an API that doesn't support Generics.. I try and isolate those calls in wrapper routines with as few lines as possible. I then use the SuppressWarnings annotation and also add the type-safety casts at the same time.

如果我必须使用不支持泛型的API。我尝试用尽可能少的行来隔离那些调用。然后,我使用抑制警告注释,并同时添加类型安全类型的转换。

This is just a personal preference to keep things as neat as possible.

这只是个人喜好,尽量保持整洁。

#16


2  

Take this one, it's much faster than creating a new HashMap, if it's already one, but still secure, as each element is checked against it's type...

以这个为例,它比创建一个新的HashMap要快得多,如果它已经是一个HashMap,但是仍然是安全的,因为每个元素都被检查为类型……

@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> toHashMap(Object input, Class<K> key, Class<V> value) {
       assert input instanceof Map : input;

       for (Map.Entry<?, ?> e : ((HashMap<?, ?>) input).entrySet()) {
           assert key.isAssignableFrom(e.getKey().getClass()) : "Map contains invalid keys";
           assert value.isAssignableFrom(e.getValue().getClass()) : "Map contains invalid values";
       }

       if (input instanceof HashMap)
           return (HashMap<K, V>) input;
       return new HashMap<K, V>((Map<K, V>) input);
    }

#17


1  

Just typecheck it before you cast it.

在你投下之前先用打字机打一下。

Object someObject = session.getAttribute("attributeKey");
if(someObject instanceof HashMap)
HashMap<String, String> theHash = (HashMap<String, String>)someObject;  

And for anyone asking, it's quite common to receive objects where you aren't sure of the type. Plenty of legacy "SOA" implementations pass around various objects that you shouldn't always trust. (The horrors!)

对于任何人来说,在不确定类型的情况下接收对象是很常见的。大量遗留的“SOA”实现传递了您不应该始终信任的各种对象。(恐怖!)

EDIT Changed the example code once to match the poster's updates, and following some comments I see that instanceof doesn't play nicely with generics. However changing the check to validate the outer object seems to play well with the commandline compiler. Revised example now posted.

编辑修改了示例代码,以匹配poster的更新,并遵循一些注释,我看到instanceof不适合泛型。但是,更改检查以验证外部对象似乎与commandline编译器很好。现在发布修改后的示例。

#18


1  

Almost every problem in Computer Science can be solved by adding a level of indirection*, or something.

计算机科学中几乎所有的问题都可以通过增加一个间接的程度来解决。

So introduce a non-generic object that is of a higher-level that a Map. With no context it isn't going to look very convincing, but anyway:

因此,引入一个非通用对象,它是一个更高级别的映射。没有上下文,它看起来不会很有说服力,但无论如何:

public final class Items implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String,String> map;
    public Items(Map<String,String> map) {
        this.map = New.immutableMap(map);
    }
    public Map<String,String> getMap() {
        return map;
    }
    @Override public String toString() {
        return map.toString();
    }
}

public final class New {
    public static <K,V> Map<K,V> immutableMap(
        Map<? extends K, ? extends V> original
    ) {
        // ... optimise as you wish...
        return Collections.unmodifiableMap(
            new HashMap<String,String>(original)
        );
    }
}

static Map<String, String> getItems(HttpSession session) {
    Items items = (Items)
        session.getAttribute("attributeKey");
    return items.getMap();
}

*Except too many levels of indirection.

*除了太多的间接方向。

#19


1  

Here's one way I handle this when I override the equals() operation.

当我重写equals()操作时,这里有一种处理方法。

public abstract class Section<T extends Section> extends Element<Section<T>> {
    Object attr1;

    /**
    * Compare one section object to another.
    *
    * @param obj the object being compared with this section object
    * @return true if this section and the other section are of the same
    * sub-class of section and their component fields are the same, false
    * otherwise
    */       
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            // this exists, but obj doesn't, so they can't be equal!
            return false;
        }

        // prepare to cast...
        Section<?> other;

        if (getClass() != obj.getClass()) {
            // looks like we're comparing apples to oranges
            return false;
        } else {
            // it must be safe to make that cast!
            other = (Section<?>) obj;
        }

        // and then I compare attributes between this and other
        return this.attr1.equals(other.attr1);
    }
}

This seems to work in Java 8 (even compiled with -Xlint:unchecked)

这似乎适用于Java 8(甚至用-Xlint编译)

#20


0  

The problem lies in here:

问题在于:

... = (HashMap<String, String>)session.getAttribute("attributeKey");

The result of session.getAttribute(...) is an object which could be anything, but since you "know" it's a HashMap<String, String> you're just casting without checking it first. Thus, the warning. To be pedantic, which Java wants you to be in this case, you should retrieve the result and verify it's compatibility with instanceof.

getattribute(…)的结果是一个可以是任何东西的对象,但是由于您“知道”它是一个HashMap ,您只是在不检查它的情况下进行转换。因此,警告。要成为pedantic, Java希望您在这种情况下,您应该检索结果并验证它与instanceof的兼容性。 ,>

#21


0  

If you are sure that the type returned by session.getAttribute() is HashMap then you can not typecast to that exact type, but rely on only checking the generic HashMap

如果您确定session.getAttribute()返回的类型是HashMap,那么您就不能对该类型进行类型转换,而是只依赖于检查通用的HashMap。

HashMap<?,?> getItems(javax.servlet.http.HttpSession session) {  
    HashMap<?,?> theHash = (HashMap<?,?>)session.getAttribute("attributeKey");
    return theHash;
} 

Eclipse will then surprise warnings, but of course this can lead to runtime errors that can be hard to debug. I use this approach in not operation-critical contexts only.

Eclipse会突然发出警告,但是这当然会导致运行时的错误,而这些错误很难调试。我只使用这种方法,而不是在操作关键的上下文中。

#22


0  

Two ways, one which avoids the tag completely, the other using a naughty but nice utility method.
The problem is pre-genericised Collections...
I believe the rule of thumb is: "cast objects one thing at a time" - what this means when trying to use raw classes in a genericised world is that because you don't know what is in this Map<?, ?> (and indeed the JVM might even find that it isn't even a Map!), it obvious when you think about it that you can't cast it. If you had a Map<String, ?> map2 then HashSet<String> keys = (HashSet<String>)map2.keySet() does not give you a warning, despite this being an "act of faith" for the compiler (because it might turn out to be a TreeSet)... but it is only a single act of faith.

PS to the objection that iterating as in my first way "is boring" and "takes time", the answer is "no pain no gain": a genericised collection is guaranteed to contain Map.Entry<String, String>s, and nothing else. You have to pay for this guarantee. When using generics systematically this payment, beautifully, takes the form of coding compliance, not machine time!
One school of thought might say that you should set Eclipse's settings to make such unchecked casts errors, rather than warnings. In that case you would have to use my first way.

有两种方法,一种是完全避免使用标签,另一种是使用一种很好的实用方法。这个问题是预生成的集合……我相信经验法则是:“一次抛一件东西”——这意味着当你试图在一个普遍的世界里使用原始的类时,因为你不知道这幅地图里有什么?>(实际上JVM甚至可能会发现它甚至不是一张地图!),当你想它时,它就很明显了。如果您有一个Map map2然后HashSet keys = (HashSet )map2. keyset()不会给您一个警告,尽管这是编译器的“信任行为”(因为它可能是一个TreeSet)……但这只是一种信念。在我的第一种方式“无聊”和“需要时间”的反对意见中,答案是“没有痛苦没有收获”:一个通用的集合被保证包含地图。输入 s,其他都没有。你必须付这个保修费。当系统地使用泛型时,很好地采用了编码遵从性的形式,而不是机器时间!一种思想流派可能会说,您应该设置Eclipse的设置,使其不受检查地抛出错误,而不是警告。在那种情况下,你必须用我的第一种方法。 ,> ,>

package scratchpad;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

public class YellowMouse {

    // First way

    Map<String, String> getHashMapStudiouslyAvoidingSuppressTag(HttpSession session) {
      Map<?, ?> theHash = (Map<?, ?>)session.getAttribute("attributeKey");

      Map<String, String> yellowMouse = new HashMap<String, String>();
      for( Map.Entry<?, ?> entry : theHash.entrySet() ){
        yellowMouse.put( (String)entry.getKey(), (String)entry.getValue() );
      }

      return yellowMouse;
    }


    // Second way

    Map<String, String> getHashMapUsingNaughtyButNiceUtilityMethod(HttpSession session) {
      return uncheckedCast( session.getAttribute("attributeKey") );
    }


    // NB this is a utility method which should be kept in your utility library. If you do that it will
    // be the *only* time in your entire life that you will have to use this particular tag!!

    @SuppressWarnings({ "unchecked" })
    public static synchronized <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }


}

#23


-1  

This makes the warnings go away...

这使得警告消失了……

 static Map<String, String> getItems(HttpSession session) {
        HashMap<?, ?> theHash1 = (HashMap<String,String>)session.getAttribute("attributeKey");
        HashMap<String,String> theHash = (HashMap<String,String>)theHash1;
    return theHash;
}

#24


-3  

Solution: Disable this warning in Eclipse. Don't @SuppressWarnings it, just disable it completely.

解决方案:在Eclipse中禁用此警告。不要警告它,只要完全禁用它。

Several of the "solutions" presented above are way out of line, making code unreadable for the sake of suppressing a silly warning.

上面提出的几个“解决方案”都是不正常的,为了抑制一个愚蠢的警告,使得代码变得不可读。