java - 了解此警告 : The serializable class does not declare a static final serialVersionUID

标签 java generics instance-initializers

我有一些静态初始化代码:

someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
  put("a","value-a"); 
  put("c","value-c");}
});

由于某种原因,我收到了来自 Eclipse 的警告: 可序列化类未声明静态最终 serialVersionUID。

这是在提示匿名类吗?我能做些什么呢,或者我应该压制它。

最佳答案

您使用的语法称为 double-brace initialization - 这实际上是一个“instance initialization blockanonymous inner class 的一部分”(当然不是黑客)。所以,当使用这个符号时,你实际上是在定义一个新的类(!)。

在您的情况下,“问题”是 HashMap实现 Serializable .此接口(interface)没有任何方法,仅用于识别可序列化的语义。换句话说,它是一个标记接口(interface),您实际上不需要实现任何东西。 但是,在反序列化过程中,Java 使用称为 serialVersionUID 的版本号来验证序列化版本是否与目标兼容。如果您不提供此serialVersionUID,则会进行计算。并且,如 Serializable 的 javadoc 中所述,计算值非常敏感,因此建议明确声明它以避免任何反序列化问题。这就是 Eclipse 所“提示”的内容(请注意,这只是一个警告)。

因此,为避免此警告,您可以在匿名内部类中添加 serialVersionUID:

someMethodThatTakesAHashMap(new HashMap<String, String>() {
    private static final long serialVersionUID = -1113582265865921787L;

    {
        put("a", "value-a");
        put("c", "value-c");
    }
});

但是你失去了语法的简洁性(你甚至可能不需要它)。

因此,另一种选择是通过在调用 someMethodThatTakesAHashMap(Map) 的方法中添加 @SuppressWarnings("serial") 来忽略警告。这似乎更适合您的情况。

总而言之,虽然这种语法简洁,但它也有一些缺点。首先,如果您持有对使用双括号初始化初始化的对象的引用,则您隐含地持有对不符合垃圾回收条件的外部对象的引用。所以要小心。其次(这听起来像是微优化),双括号初始化有一个 very a little bit of overhead .第三,正如我们所见,这种技术实际上使用了匿名内部类,因此占用了一些 permgen 空间(但我怀疑这真的是一个问题,除非你真的滥用它们)。最后——这可能是最重要的一点——我不确定它是否使代码更具可读性(这不是众所周知的语法)。

所以,虽然我喜欢在测试中使用它(为了简洁起见),但我倾向于避免在“常规”代码中使用它。

关于java - 了解此警告 : The serializable class does not declare a static final serialVersionUID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1514881/

相关文章:

java - 从非静态上下文调用同一个类的java构造函数会导致递归,但是使用静态它可以正常工作吗?

java - 如何将实例初始值设定项与通用 HashMap 一起使用?

Swift:如何在类中初始化类的实例

java - 在 ant build 中加速 junit 测试

java - 重载采用通用类型的方法会导致模棱两可的方法调用编译错误

java虚拟机: type information

java - RxJava Single/Observable 返回接口(interface)的实现

swift - 从字符串中检索的强制转换类类型

java在泛型方法中使用this(继承)

java - 将用户组分配给角色 - Liferay 6.1.1