Java 如何处理未检查的强制转换警告?

Java 如何处理未检查的强制转换警告?,java,generics,warnings,Java,Generics,Warnings,Eclipse向我发出以下形式的警告: 类型安全性:未选中从对象到HashMap的强制转换 这是对API的调用,我无法控制该API返回的对象: HashMap<String, String> getItems(javax.servlet.http.HttpSession session) { HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("at

Eclipse向我发出以下形式的警告:

类型安全性:未选中从对象到HashMap的强制转换

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

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
  HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
  return theHash;
}
当您尝试使用哈希时,问题出现在其他地方,您会收到警告:

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.
HashMap items=getItems(会话);
项目。放入(“该”、“该”);
类型安全:方法put(Object,Object)属于原始类型HashMap。对泛型类型HashMap的引用应该参数化。

如果你发布你的代码,快速猜测可以肯定,但你可能已经按照

HashMap<String, Object> test = new HashMap();
HashMap test=newhashmap();
当你需要做的时候会产生警告

HashMap<String, Object> test = new HashMap<String, Object>();
HashMap test=newhashmap();
这可能值得一看


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

我可能误解了这个问题(一个示例和几行环绕的行就好了),但是为什么您不总是使用适当的接口(和Java5+)?我看不出你有什么理由想要转换成
HashMap
而不是
Map
。事实上,我无法想象有什么理由将变量的类型设置为
HashMap
,而不是
Map


为什么源是
对象
?它是旧集合的参数类型吗?如果是这样,请使用泛型并指定所需的类型。

显然,答案不是执行未选中的强制转换

如果绝对必要,那么至少尝试限制
@SuppressWarnings
注释的范围。根据its,它可以处理局部变量;这样,它甚至不会影响整个方法

例如:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();
@SuppressWarnings(“未选中”)
Map myMap=(Map)反序列化映射();

无法确定
映射
是否真的应该具有通用参数
。您必须事先知道参数应该是什么(或者当您得到
ClassCastException
时就会知道)。这就是代码生成警告的原因,因为编译器不可能知道是否安全。

在强制转换之前只需键入检查即可

Object someObject = session.getAttribute("attributeKey");
if(someObject instanceof HashMap)
HashMap<String, String> theHash = (HashMap<String, String>)someObject;  
objectsomeobject=session.getAttribute(“attributeKey”);
if(HashMap的someObject实例)
HashMap theHash=(HashMap)someObject;
对于任何询问的人来说,在不确定对象类型的情况下接收对象是很常见的。许多遗留的“SOA”实现传递各种您不应该总是信任的对象。(恐怖!)


EDIT将示例代码更改了一次,以匹配海报的更新,在一些评论之后,我发现instanceof不能很好地处理泛型。但是,更改检查以验证外部对象似乎与命令行编译器配合得很好。修订后的示例现已发布。

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

问题是演员阵容没有被检查。所以,你必须亲自检查。不能仅使用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;
}
公共静态HashMap castHash(HashMap输入,
类键类,
类值(类){
HashMap输出=新的HashMap();
如果(输入==null)
返回输出;
for(对象键:input.keySet().toArray()){
if((key==null)| |(keyClass.isAssignableFrom(key.getClass())){
对象值=输入。获取(键);
if((value==null)| |(valueClass.isAssignableFrom(value.getClass())){
K=keyClass.cast(键);
V=价值等级.cast(价值);
输出电压(k,v);
}否则{
抛出新断言错误(
“无法强制转换为HashMap”
+,值“+value+”不是“+valueClass.getSimpleName()
);
}
}否则{
抛出新断言错误(
“无法强制转换为HashMap”
+,键“+key+”不是“+keyClass.getSimpleName()
);
}
}
返回输出;
}

这是一个很大的工作,可能只有很少的报酬。。。我不确定我是否会用它。我很感激任何关于人们是否认为值得的评论。此外,我也希望得到改进建议:除了抛出断言错误,我还能做些更好的事情吗?有更好的吗?我应该将其设置为选中的异常吗?

不幸的是,这里没有很好的选项。请记住,所有这些的目标都是保护类型安全。“”提供了一种处理非泛型遗留库的解决方案,在第8.2节中有一种特别称为“空循环技术”。基本上,进行不安全强制转换,并抑制警告。然后像这样在地图上循环:

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());
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);
    }
}
@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;
@SuppressWarnings(“未选中”)
Map Map=getMap();
for(字符串s:map.keySet());
for(编号n:map.values());

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

如果我必须使用不支持泛型的API。。我尝试用尽可能少的行在包装器例程中隔离这些调用。然后,我使用SuppressWarnings注释并添加ty
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);
    }
}
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();
}
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);
    }
}
HashMap<?,?> getItems(javax.servlet.http.HttpSession session) {  
    HashMap<?,?> theHash = (HashMap<?,?>)session.getAttribute("attributeKey");
    return theHash;
} 
 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;
}
@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);
    }
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;
    }


}
@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
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);
    }
}
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;
}
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();
}
dragFinishedStrategy.dragFinished(viewer, Product.class);
//noinspection unchecked
Map<String, String> myMap = (Map<String, String>) deserializeMap();