理解此警告:可序列化类并未声明静态最终序列化uID
-
19-09-2019 - |
题
我有一些静态初始化器代码:
someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
put("a","value-a");
put("c","value-c");}
});
由于某种原因,我正在收到Eclipse的警告:可序列化类并未声明静态的最终序列化uID。
这是在抱怨匿名课程吗?我该怎么办,或者我应该抑制它。
解决方案
您正在使用的语法称为 双臂初始化 - 实际上是实例初始化块 那是一个 匿名内部类“(当然不是黑客)。因此,使用此符号时,您实际上是在定义新类(!)。
在您的情况下,“问题”是 HashMap
工具 Serializable
. 。此接口没有任何方法, 仅供识别可序列化的语义. 。换句话说,这是一个标记界面,您不必实现任何东西。 但, ,期间,Java使用称为A的版本号 serialVersionUID
验证序列化版本是否与目标兼容。如果您不提供这个 serialVersionUID
, ,将计算。并且,如在Javadoc的Javadoc所记录 Serializable
, ,计算的值非常敏感,因此建议明确声明它以避免任何挑选问题。这就是Eclipse的“抱怨”(请注意,这只是一个警告)。
因此,为避免此警告,您可以添加 serialVersionUID
到您的匿名内部类:
someMethodThatTakesAHashMap(new HashMap<String, String>() {
private static final long serialVersionUID = -1113582265865921787L;
{
put("a", "value-a");
put("c", "value-c");
}
});
但是,您会失去语法的简洁性(您甚至不需要它)。
因此,另一个选择是通过添加一个来忽略警告 @SuppressWarnings("serial")
到您正在调用的方法 someMethodThatTakesAHashMap(Map)
. 。就您而言,这似乎更合适。
这就是说,尽管这种语法简洁,但它有一些缺点。首先,如果您使用双撑架初始化对对象进行了参考,则隐式地保存对不符合垃圾收集资格的外部对象的引用。所以要小心。第二(尽管这听起来像是微型优化),双扶手初始化具有 一点点开销. 。第三,这项技术实际上是我们所看到的匿名内部类,从而吃了一些permgen空间(但我怀疑这确实是一个问题,除非您 真的 虐待他们)。最后 - 这也许是最重要的一点 - 我不确定它使代码更可读(这不是一个知名的语法)。
因此,尽管我喜欢在测试中使用它(为了简洁),但我倾向于避免在“常规”代码中使用它。
其他提示
是的,您可以抑制警告,但是我会这样重写:
HashMap<String, String> map = new HashMap<String, String>();
map.put("a","value-a");
map.put("c","value-c");
someMethodThatTakesAHashMap(map);
不需要抑制,读书也更好,IMO。
我通常同意Bart K.,但出于信息目的:
也可以通过添加字段来消除警告,可以通过击中CTRL+1自动生成。
在定义之前,还可以添加@suppresswarnings(“序列”)注释来抑制警告。
匿名类实现可序列化的实现,并且可序列化需要此静态字段,以便在序列化和去除序列化时可以区分版本。更多信息在这里:
http://www.javablogging.com/what-is-serialversionuid/
这 ImmutableMap
Google Collections库的课程对这种情况很有用。例如
someMethodThatTakesAHashMap(ImmutableMap.<K, V>builder().put("a","value-a").put("c","value-c").build());
或者
someMethodThatTakesAHashMap(ImmutableMap.of("a","value-a","c","value-c"));
要解决您的问题的另一半,“我应该抑制它吗?” - -
是的。我认为,这是一个可怕的警告。默认情况下应 不是 被使用,而不是相反。
如果您不添加serialversionuid,则发生的最糟糕的事情是,实际上与序列化兼容的对象的两个版本被认为是不兼容的。 SerialVersionuID是宣布序列化兼容性没有改变的一种方式,从而覆盖了Java的默认评估。
使用serialversionuid,发生的最糟糕的事情是,当类的序列化形式以不兼容的方式变化时,您会无意中无法更新ID。充其量,您还会遇到运行时错误。在最坏的情况下,情况更糟。并想象一下无法更新它是多么容易。
您的目的是初始化哈希图的匿名实例。警告是您的代码所做的比您预期的要多。
我们正在寻找的是一种初始化匿名哈希图实例的方法。上面我们创建了一个匿名子类的哈希图,然后创建了该匿名类的匿名实例。
因为代码的作用比预期的要多,所以我称其为黑客。
我们真正想要的就是这样:
foo(new HashMap<String, String>({"a", "value-a"}, {"c", "value-c"}));
但是可惜这不是有效的爪哇。没有一种方法可以使用键/值对数组以类型的安全方式进行操作。 Java Simple没有表达能力。
Google Collection的ImmutableMap.of静态方法很接近,但这意味着为各种键/值对创建工厂方法的版本。 (请参阅Finnw的答案。)
因此,请保持简单。使用Bart K的解决方案,除非您的代码对此初始化乱扔垃圾。如果是这样,请使用ImmutableMap。或使用“”样式工厂方法滚动自己的哈希图子类。或在实用程序类中创建这些“”样式工厂方法。这是两个键/值对的一对:
public final MapUtil {
public static <K,V> Map<K,V> makeMap(K k1, V v1, K k2, V v2) {
Map<K,V> m = new HashMap<K,V>();
m.put(k1, v1);
m.put(k2, v2);
return m;
}
}
拥抱冗长,并在您的公司同事戴着与您相同的束缚的知识中慰藉。