Java 反序列化集合时的不安全泛型强制转换 公共配置(节点、文件){ HashMap conf=(HashMap)SerializationUtils.deserialize(新文件输入流(file)); }

Java 反序列化集合时的不安全泛型强制转换 公共配置(节点、文件){ HashMap conf=(HashMap)SerializationUtils.deserialize(新文件输入流(file)); },java,generics,serialization,casting,Java,Generics,Serialization,Casting,我理解为什么这会给出一个不安全的施法警告,但是安全的最佳/公认的方法是什么?有什么好办法吗?您不能仅使用Java语言以完全类型安全的方式处理这种情况 因为这是一件必须重复执行的事情,您无法真正绕过它,所以我建议使用genreic方法来读取和转换通用对象: public Configuration(Node node, File file) { HashMap<String, String> conf = (HashMap<String, String>) Seri

我理解为什么这会给出一个不安全的施法警告,但是安全的最佳/公认的方法是什么?有什么好办法吗?

您不能仅使用Java语言以完全类型安全的方式处理这种情况

因为这是一件必须重复执行的事情,您无法真正绕过它,所以我建议使用genreic方法来读取和转换通用对象:

public Configuration(Node node, File file) {
    HashMap<String, String> conf = (HashMap<String, String>) SerializationUtils.deserialize(new FileInputStream(file));
}
@SuppressWarnings(“未选中”)
公共静态读取对象(
ObjectInputStream输入
)抛出IOException,ClassNotFoundException{
在.readObject()中返回(T);
}

但是,我建议您通常不要使用这样的方法来抑制有效的警告。

实际上没有任何方法可以正确地做到这一点,因为您要检查的编译时类型信息(即
String
)在运行时(即实际发生强制转换时)不可用通过称为擦除的过程。我认为最好的方法是让你通过一些定制的“棋盘格”传递你的反序列化收藏:

Map conf=反序列化(rsrc);
Map checked=checkMap(conf,String.class,String.class);
//可以免费使用
其中:

Map<?,?> conf = deserialize(rsrc);
Map<String, String> checked = checkMap(conf, String.class, String.class);
//can use checked freely
@SuppressWarnings(“未选中”)
公共静态地图检查地图(地图地图,e类:地图){
k、 cast(e.getKey());//将抛出ClassCastException
v、 cast(如getValue());
}
返回(地图)地图//未经检查
}

在前面的答案的基础上,我通常会在抑制警告时更进一步。我将注释放在局部变量上而不是方法上,以减少抑制范围。这意味着,如果以后有人来添加该方法,则不会出现无意的抑制。它确实增加了另一行代码,但我认为这种权衡是值得的

@SuppressWarnings("unchecked")
public static <K, V> Map<K,V> checkMap(Map<?,?> map, Class<? extends K> k, Class<? extends V> v) {
    for (Map.Entry<?, ?> e : map) {
        k.cast(e.getKey());   //will throw ClassCastException
        v.cast(e.getValue());
    }
    return (Map<K,V>) map; //unchecked 
}
publicstatict读取对象(
ObjectInputStream输入
)抛出IOException,ClassNotFoundException{
@抑制警告(“未选中”)
T val=(T)in.readObject();
返回val;
}

不幸的是,您无法向表达式添加注释(至少还没有)。

这正是我所担心的;我只是希望我遗漏了什么:/这是一个有效的警告,只有在一个坏的语言功能设计的背景下!如果没有类型擦除,我们将无法反序列化这些对象。我认为这是一场胜利。有人想解释一下为什么一个完全正确的答案被否决了吗?这是因为我有可能否决了一个无效且不正确的答案吗?我不是否决者,但我可以看出,这在多线程访问的情况下可能不起作用。一个线程运行检查器,而另一个线程使用原始引用在检查后插入“错误”类型。Boom,ClassCastException.@Steven-我不认为“在多线程环境中可能不安全”一定是这种
检查方法的错误。我在回答中增加了一点细节。该方法根本不是设计为以这种方式工作的,可以记录下来,因此我倾向于在该方法上添加注释,因为该方法的整个要点是抑制警告。
@SuppressWarnings("unchecked")
public static <K, V> Map<K,V> checkMap(Map<?,?> map, Class<? extends K> k, Class<? extends V> v) {
    for (Map.Entry<?, ?> e : map) {
        k.cast(e.getKey());   //will throw ClassCastException
        v.cast(e.getValue());
    }
    return (Map<K,V>) map; //unchecked 
}
public static <T> T readObject(
    ObjectInputStream in
) throws IOException, ClassNotFoundException {
    @SuppressWarnings("unchecked")
    T val = (T)in.readObject();
    return val;
}