如何解决未经检查的演员表警告?


610

Eclipse给我以下形式的警告:

类型安全性:未经检查的从Object到HashMap的转换

这是从对我无法控制返回对象的API的调用中得出的:

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

如果可能的话,我想避免Eclipse警告,因为从理论上讲,它们至少表明潜在的代码问题。不过,我还没有找到消除这种情况的好方法。我可以将涉及到的单行本身提取到一个方法中,然后添加@SuppressWarnings("unchecked")到该方法中,从而在我忽略警告的地方限制了代码块的影响。还有更好的选择吗?我不想在Eclipse中关闭这些警告。

在我接触代码之前,它比较简单,但是仍然会引发警告:

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

当您尝试使用哈希时,问题出在其他地方,您将得到警告:

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.

如果您使用的是HttpSession,请查看Brian Goetz关于该主题的文章:ibm.com/developerworks/library/j-jtp09238.html
Tom Hawtin-tackline

如果不可避免地要进行强制转换,那么一个好主意是将其与逻辑上表示其类型的对象紧密结合(例如,enum甚至是的实例Class<T>),这样您就可以浏览一下并知道它是安全的。
菲利普·金



我要添加的是,我发现只能在包含违规代码的方法级别添加@SuppressWarnings(“ unchecked”)。因此,我将代码分解为必须执行的例程。我一直认为您可以在相关行上方立即执行此操作。
JGFMK

Answers:


557

当然,显而易见的答案是不要进行未经检查的转换。

如果绝对必要,则至少尝试限制@SuppressWarnings注释的范围。根据其Javadocs,它可以使用局部变量。这样,它甚至不会影响整个方法。

例:

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

无法确定是否Map真正应该具有通用参数<String, String>。您必须事先知道参数应该是什么(否则您将在找到时发现ClassCastException)。这就是代码生成警告的原因,因为编译器可能无法知道是否安全。


112
+1指出它可以使用局部变量。Eclipse仅提供将其添加到整个方法中……
thSoft,2010年

17
Eclipse 3.7(Indigo)支持将未检查的添加到局部变量。
sweetfa

78
警告不只是因为编译器不知道强制转换是安全的。例如String s = (String) new Object() ;,即使编译器不知道强制转换是安全的,也不会发出警告。该警告是因为编译器(a)不知道强制转换是安全的,并且(b)不会在强制转换时生成完整的运行时检查。将检查是否为Hashmap,但不会检查为HashMap<String,String>
Theodore Norvell

9
不幸的是,即使强制转换和警告用于赋值,注释也必须放在变量声明中……因此,如果声明和赋值位于不同的位置(例如,分别在“ try”块的内部和内部) ,Eclipse现在会生成两个警告:原始未检查的强制转换和新的“不必要的注释”诊断。
Ti Strga

6
需要与局部变量声明一起使用的批注的变通方法是在实际的转换范围内创建局部变量,以专门在同一行执行转换,该注解可能与实际转换在不同的行中位于不同的范围内作为声明。然后将此变量分配给范围不同的实际变量。这也是我用来抑制对实例变量进行强制转换的警告的方法,因为注释也无法在此处应用。
杰夫·洛克哈特

167

不幸的是,这里没有很好的选择。请记住,所有这些的目的是保持类型安全。“ Java泛型 ”提供了一种用于处理非泛型遗留库的解决方案,第8.2节中特别提到了一种“空循环技术”。基本上,进行不安全的投射,并抑制警告。然后像这样遍历地图:

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

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


6
答案比skiphoppy提供的答案好得多,原因有很多:1)此代码短得多了。2)此代码实际上会按预期引发ClassCastException。3)此代码不会完整复制源地图。4)循环可以很容易地包装在断言中使用的单独方法中,这很容易消除生产代码中的性能问题。
Stijn de Witt 2014年

6
Java编译器或JIT编译器是否有可能确定该代码的结果未被使用并通过不对其进行“优化”?
RenniePet 2014年

1
如果它可能引发异常,它并不是真正的无效代码。我对目前使用的JIT编译器了解不足,无法保证它们不会弄乱这一点,但是我很自信地说它们不应该这样做。
GrandOpener

3
这仍然不能保证类型安全,因为仍在使用同一映射。它最初可能被定义为Map <Object,Object>,而恰好恰好在其中包含了字符串和数字,然后再添加一个布尔值,则此代码的用户将感到困惑,并且很难追踪到惊喜。保证类型安全的唯一方法是将其复制到具有所请求类型的新映射中,以保证允许输入的内容。
user2219808 '18

112

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

问题是没有检查演员表。因此,您必须自己检查它。您不能只使用instanceof检查参数化类型,因为参数化类型信息在运行时不可用,在编译时已被擦除。

但是,您可以使用instanceof对散列中的每个项目执行检查,并以此来构造类型安全的新散列。而且您不会招来任何警告。

感谢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;
}

这项工作很繁琐,可能只获得很少的报酬...我不确定是否会使用它。对于人们认为是否值得的任何评论,我将不胜感激。另外,我也很高兴提出改进建议:除了抛出AssertionErrors之外,我还能做些更好的事情吗?有什么我可以扔的更好的东西吗?我应该将其设为检查异常吗?


68
这些东西令人困惑,但是我认为您所做的只是将ClassCastExceptions换为AssertionErrors。
Dustin Getz

59
杜德,那绝对不值得!想象一下可怜的树液,他必须回来并在那里修改一些混乱的代码。我不喜欢抑制警告,但是我认为这是较小的邪恶。
Craig B

69
这不仅是一个丑陋,令人困惑的混乱(当您无法避免一个丰富的注释可以使维护程序员逐步解决时);对集合中的每个元素进行迭代将转换从O(1)转换为O(n)操作。这是始料未及的,并且很容易变成可怕的神秘减速。
Dan在Firelight摆弄

22
@DanNeely,您是正确的。通常,没有人应该这样做。
skiphoppy 2012年

4
一些评论...方法签名是错误的,因为它不会“投射”该死的东西,它只是将现有地图复制到新地图中。另外,它可能可以重构为接受任何映射,而不依赖HashMap本身(即,即使内部类型为HashMap,也要在方法签名中获取Map并返回Map)。您实际上并不需要将其转换或存储到新的映射中-如果您没有引发断言错误,那么截至目前,给定的映射内部具有正确的类型。使用泛型类型创建新地图毫无意义,因为您仍然可以将其原始并放置任何内容。
MetroidFan2002

51

在Eclipse首选项中,转到Java->编译器->错误/警告->通用类型,然后选中Ignore unavoidable generic type problems复选框。

这满足了问题的意图,即

我想避免Eclipse警告...

如果没有精神。


1
嗯,谢谢:)我在中遇到了一个“ uses unchecked or unsafe operations.”错误javac,但是添加@SuppressWarnings("unchecked")使Eclipse感到不满,声称不需要进行抑制。 取消选中此框会使Eclipse的javac行为相同,这正是我想要的。在代码中明确禁止警告比在Eclipse内部各处禁止警告要清晰得多。
dimo414

26

您可以创建如下所示的实用程序类,并使用它来抑制未选中的警告。

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;
    }
}

您可以按以下方式使用它:

import static Objects.uncheckedCast;
...

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

关于此的更多讨论在这里:http : //cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html


18
而不是拒绝投票,但是包装器仅在抑制警告方面没有添加任何东西。
达斯汀·盖兹

3
+1,因为此解决方案不会浪费宝贵的代码行。
蒂诺2014年

1
@ErikE太多了。更昂贵的更大,更高分辨率的显示器可以为所有这些浪费的线路留出空间,更大的桌子可以放置所有更大的显示器,更大的房间可以放置更大的显示器,以及有见识的老板..
蒂诺

1
@ErikE滚动条,用于vi你在开玩笑吗?
蒂诺

21

这些东西很难,但是这是我目前的想法:

如果您的API返回Object,那么您将无能为力-无论如何,您将盲目地投射对象。您可以让Java抛出ClassCastExceptions,或者您可以自己检查每个元素并抛出Assertions或IllegalArgumentExceptions或类似的东西,但是这些运行时检查都是等效的。您必须抑制编译时间无论您在运行时执行什么操作,取消选中。

我只希望盲目转换,让JVM为我执行运行时检查,因为我们“知道” API应该返回什么,并且通常愿意假定API可以工作。如果需要,请在演员表上方的各处使用泛型。由于您仍然只进行盲目转换,因此您并没有真正在此购买任何东西,但是至少您可以从那里开始使用泛型,因此JVM可以帮助您避免在代码的其他部分盲目转换。

在这种特殊情况下,大概您可以看到对SetAttribute的调用,并看到类型即将传入,因此在输出时将类型盲目转换为相同类型并不是不道德的。添加引用SetAttribute的注释并完成它。


16

这是一个简短的示例,它通过采用其他答案中提到的两种策略来避免“未选中的强制转换”警告

  1. 在运行时(Class<T> inputElementClazz)传递感兴趣类型的Class作为参数。然后,您可以使用:inputElementClazz.cast(anyObject);

  2. 对于Collection的类型转换,请使用通配符?。而不是通用类型T来承认您确实不知道从旧代码(Collection<?> unknownTypeCollection)中期望什么样的对象。毕竟,这就是“未经检查的演员表”警告要告诉我们的:我们不能确定我们得到了a Collection<T>,因此诚实的做法是使用a Collection<?>。如果绝对需要,仍可以构建已知类型的集合(Collection<T> knownTypeCollection)。

在下面的示例中连接的传统代码在StructuredViewer中具有属性“ 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();
}

自然,如果我们使用具有错误数据类型的旧代码,则上面的代码会给运行时错误(例如,如果将数组设置为StructuredViewer的“输入”而不是Java集合)。

调用方法的示例:

dragFinishedStrategy.dragFinished(viewer, Product.class);

13

在HTTP会话世界中,您真的无法避免强制类型转换,因为API是以这种方式编写的(仅接受和返回) Object)。

通过一点点的工作,您就可以轻松避免未经检查的演员。这意味着它会变成传统的强制类型转换ClassCastException,以防出现错误。未经检查的异常可能会CCE在以后的任何时候变为,而不是强制转换的点(这就是它是单独警告的原因)。

将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);
    }
}

然后将其强制转换为该类,而不是Map<String,String>所有内容,将在编写代码的确切位置检查所有内容。ClassCastExceptions以后没有意外。


这确实是很有帮助的答案。
GPrathap 2015年

10

在Android Studio中,如果您要禁用检查,可以使用:

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

2
这也可以在IntelliJ IDE中使用
-neXus

8

在这种情况下,我不会将Maps直接存储到HttpSession中,而是将自己的类的实例存储到自己的类中,而该类又包含一个Map(该类的实现细节)。然后,您可以确保地图中的元素类型正确。

但是,如果您仍然想检查Map的内容是否正确,则可以使用如下代码:

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);
    }
}

1
太棒了 我想我可以将其与我的答案结合起来进行参数化,而不必完全消除警告!
skiphoppy

1
+1可能是最好的配方(易于理解和维护),可通过运行时检查安全地进行操作
Tino 2014年

8

Esko Luontola的上述答案中的Objects.Unchecked实用程序功能是避免程序混乱的好方法。

如果您不希望将SuppressWarnings应用于整个方法,则Java会强制您将其放在本地。如果您需要对成员进行强制转换,则可能会导致如下代码:

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

使用该实用程序更加简洁,而且您在做什么仍然很明显:

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

注意: 我觉得很重要的一点是,有时警告确实表示您在做错事,例如:

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

编译器告诉您的是,在运行时不会检查此强制转换,因此在尝试访问通用容器中的数据之前,不会引发运行时错误。


5

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

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;
}

1
他五岁的问题?您需要做很多工作吗?鉴于Java具有类型擦除,第二个哈希图在运行时应与第一个相同。我认为这样做会更有效,并且如果您只是遍历条目并验证它们都是字符串实例,则避免复制。或者,TBH,检查您正在使用的servlet JAR的来源,并验证它是否仅放入了字符串。
Rup

1
到目前为止,我在项目中看到了此警告。他的问题不是验证类型,而是由“放”入未铸造地图引起的警告。
阿巴斯2015年

2

如果您发布代码,可以快速猜测一下,虽然可以肯定地说,但是您可能已经做了一些事情,例如

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

当您需要这样做时会产生警告

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

也许值得一看

Java编程语言中的泛型

如果您不熟悉需要做什么。


1
不幸的是,情况并非如此简单。代码已添加。
skiphoppy

1
我来这里的目的是寻找一个稍有不同的问题的答案:您告诉我的正是我所需要的!谢谢!
staticsan

2

我可能误解了这个问题(一个示例和一些周围的线条会很好),但是为什么不总是使用适当的接口(和Java5 +)呢?我看不出您为什么要转换成a HashMap而不是a的理由Map<KeyType,ValueType>。实际上,我无法想象有任何理由将变量的类型设置HashMapMap

以及来源为何Object?它是旧式集合的参数类型吗?如果是这样,请使用泛型并指定所需的类型。


2
我很确定在这种情况下切换到Map不会改变任何东西,但是感谢编程技巧,它可能会改变我做某些事情的方式,从而更好。对象的来源是我无法控制的API(添加了代码)。
skiphoppy

2

如果我必须使用不支持泛型的API。我尝试以尽可能少的行将这些调用隔离在包装程序中。然后,我使用SuppressWarnings批注,并同时添加类型安全强制类型转换。

这只是使事情保持整洁的个人喜好。


2

拿这个,它比创建一个新的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);
    }

key.isAssignableFrom(e.getKey().getClass())可以写成key.isInstance(e.getKey())
user102008 2011年

1

只需在投放前进行类型检查即可。

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

对于任何询问的人,接收不确定类型的对象都是很常见的。许多传统的“ SOA”实现绕过了您不应该始终信任的各种对象。(恐怖!)

编辑一次更改了示例代码,以匹配发布者的更新,并且在进行了一些注释之后,我发现instanceof与泛型不能很好地配合使用。但是,更改检查以验证外部对象似乎可以在命令行编译器中很好地发挥作用。现在发布修改后的示例。


8
不幸的是,泛型使这不可能。它不仅仅是一个HashMap,它还是具有类型信息的HashMap。如果我消除了这些信息,我只会将警告发送到其他地方。
skiphoppy

1

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

因此,引入一个比a更高级别的非通用对象Map。在没有上下文的情况下,它看起来不会很令人信服,但无论如何:

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

*除了太多级别的间接。


1
引述归功于已故的大卫·惠勒教授。 en.wikipedia.org/wiki/...
斯蒂芬ç

1

这是我重写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);
    }
}

这似乎在Java 8中有效(甚至使用编译-Xlint:unchecked


0

如果您确定session.getAttribute()返回的类型是HashMap,则不能将其类型转换为该确切类型,而只能依靠检查常规HashMap

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

Eclipse将使警告变得意外,但是,这当然会导致难以调试的运行时错误。我仅在非关键操作环境中使用此方法。


0

有两种方法,一种完全避免使用标记,另一种则使用顽皮但实用的实用程序方法。
问题是预先生成的Collections ...
我相信经验法则是:“一次投射对象一件事”-在通用世界中尝试使用原始类时,这意味着因为您不知道什么在此Map <?,?>中(实际上JVM甚至可能发现它甚至都不是Map!),当您考虑它时就很明显无法进行转换。如果您有Map <String,?> map2,则HashSet <String> keys =(HashSet <String>)map2.keySet()不会给您警告,尽管这是编译器的“信念行为”(因为它可能会变成是一个TreeSet)...但它只是一个单一的信心的行动。

PS反对以我的第一种方式迭代“很无聊”和“花费时间”的反对意见,答案是“不费吹灰之力”:保证泛型集合包含Map.Entry <String,String> 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;
    }


}

您没有评论权限的事实不允许您编辑其他人的答案以添加评论;您可以编辑他人的答案,以改善格式,语法等方面的意见,而不是对他人发表意见。当您达到50个代表时,您将可以在任何地方发表评论,与此同时,我确信您可以抗拒(或者,如果您确实不能发表评论,则将评论写到帖子中现有的答案上)。(给其他人的提示:我写这封信是因为我看到并拒绝了他对审核工具中其他帖子的建议评论编辑)
Matteo Italia

-1

这使警告消失了...

 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;
}

1
不,不是。实际上,这会在首先出现一个警告的情况下创建两个警告。
Stijn de Witt

喔好吧。不知道为什么我会那样想。
lukewm 2014年

-3

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

上面介绍的几个“解决方案”与众不同,为了抑制愚蠢的警告,使代码不可读。


9
请问为什么?全局禁用警告将隐藏此问题所在的其他地方。添加a @SuppressWarnings不会使代码根本不可读。
MByD
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.