反序列化集合时出现不安全的通用转换

8
public Configuration(Node node, File file) {
    HashMap<String, String> conf = (HashMap<String, String>) SerializationUtils.deserialize(new FileInputStream(file));
}

我明白为什么会出现不安全的转换警告,但是有没有最好/被接受的方法来安全地执行这个操作?是否有任何好的方法?

3个回答

2

仅使用Java语言无法完全以类型安全的方式处理此情况。

由于这是必须反复执行的操作,而且你真的无法绕过它,我建议使用一种通用方法来读取和转换通用对象:

@SuppressWarnings("unchecked")
public static <T> T readObject(
    ObjectInputStream in
) throws IOException, ClassNotFoundException {
    return (T)in.readObject();
}

然而,我建议您不要通常使用此类方法来抑制有效的警告。


这正是我担心的,只是希望我漏掉了什么:/ - Steven Schlansker
只有在语言特性设计有问题的情况下,这才是一个有效的警告! - Jonathan Feinberg
1
如果没有类型擦除,我们将无法反序列化这些对象。我认为这是一种胜利。 - Tom Hawtin - tackline

2

由于在运行时(即发生强制转换时)通过称为“擦除”的过程无法获得所需的编译时类型信息(即String),因此没有真正正确的方法来执行此操作。我认为最好的方法是将反序列化的集合传递给一些定制的“检查器”:

Map<?,?> conf = deserialize(rsrc);
Map<String, String> checked = checkMap(conf, String.class, String.class);
//can use checked freely

其中:

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

有人能解释一下为什么一个完全有效和正确的答案被踩了吗?是因为我不小心踩了一个无效和错误的答案吗? - oxbow_lakes
我不是那个给你点踩的人,但我可以看出在多线程访问的情况下这可能行不通。一个线程运行检查器,而另一个在检查后使用原始引用插入“错误”的类型。瞬间,就会出现ClassCastException。 - Steven Schlansker
@Steven - 我认为“在多线程环境中可能不安全”并不一定是这种 check 方法的错误。我已经在我的答案中添加了更多细节。该方法只是没有设计成以这种方式工作,因此可以如此记录文档。 - oxbow_lakes

1
为了进一步完善之前的答案,当我抑制警告时,通常会更进一步。我将注释放在局部变量上,而不是方法上,以减少抑制的范围。这意味着如果有人稍后修改该方法,就不会出现意外的抑制。虽然这会增加一行代码,但我认为这种权衡是值得的。
public static <T> T readObject(
    ObjectInputStream in
) throws IOException, ClassNotFoundException {
    @SuppressWarnings("unchecked")
    T val = (T)in.readObject();
    return val;
}

很遗憾,您目前无法向表达式添加注释(至少还不行)。


我倾向于在方法上放置注释,因为方法的整个目的是抑制警告。 - Tom Hawtin - tackline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接