了解此警告:可序列化类不声明静态最终序列VersionUID
我有一些静态初始值设定项代码:
someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
put("a","value-a");
put("c","value-c");}
});
出于某种原因,我收到了来自Eclipse的警告:可序列化类不会声明静态的最终串行VersionUID。
这是在抱怨匿名类吗?我能做些什么,或者我应该压制它。
我有一些静态初始值设定项代码:
someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
put("a","value-a");
put("c","value-c");}
});
出于某种原因,我收到了来自Eclipse的警告:可序列化类不会声明静态的最终串行VersionUID。
这是在抱怨匿名类吗?我能做些什么,或者我应该压制它。
您使用的语法称为双大括号初始化 - 这实际上是一个“作为匿名内部类一部分的实例初始化块”(当然不是黑客)。因此,当使用此表示法时,您实际上是在定义一个新类(!)。
您案例中的“问题”是HashMap
实现了Serializable
。此接口没有任何方法,仅用于标识可序列化的语义。换句话说,它是一个标记接口,你不需要实现任何东西。但是,在反序列化期间,Java 使用称为 a 的版本号来验证序列化版本是否与目标兼容。如果您不提供此信息,则将进行计算。而且,正如Serializable
的javadoc中所记录的那样,计算的值非常敏感,因此建议显式声明它以避免任何反序列化问题。这就是Eclipse“抱怨”的原因(请注意,这只是一个警告)。serialVersionUID
serialVersionUID
因此,为了避免此警告,您可以向匿名内部类添加一个:serialVersionUID
someMethodThatTakesAHashMap(new HashMap<String, String>() {
private static final long serialVersionUID = -1113582265865921787L;
{
put("a", "value-a");
put("c", "value-c");
}
});
但是你失去了语法的简洁性(你甚至可能不需要它)。
因此,另一种选择是通过向要调用 的方法添加 a 来忽略警告。这在您的情况下似乎更合适。@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。