java 了解此警告:可序列化类未声明静态最终 serialVersionUID
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1514881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding this warning: The serializable class does not declare a static final serialVersionUID
提问by Alex Baranosky
I have some static initializer code:
我有一些静态初始化代码:
someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
put("a","value-a");
put("c","value-c");}
});
For some reason I am receiving a warning from Eclipse: The serializable class does not declare a static final serialVersionUID.
出于某种原因,我收到了来自 Eclipse 的警告:可序列化类未声明静态最终 serialVersionUID。
Is this complaining about the anonymous class? What can I do about that, or should I just suppress it.
这是在抱怨匿名课程吗?我该怎么办,或者我应该压制它。
回答by Pascal Thivent
The syntax you're using is called double-brace initialization- which is actually an "instance initialization blockthat is part of an anonymous inner class" (certainly not a hack). So, when using this notation, you are actually defining a new class(!).
您使用的语法称为双括号初始化- 它实际上是一个“实例初始化块,它是匿名内部类的一部分”(当然不是黑客)。因此,当使用这种表示法时,您实际上是在定义一个新类(!)。
The "problem" in your case is that HashMapimplements Serializable. This interface doesn't have any methods and serves only to identify the semantics of being serializable. In other words, it's a marker interface and you concretely don't have to implement anything. But, during deserialization, Java uses a version number called a serialVersionUIDto verify that the serialized version is compatible with the target. If you don't provide this serialVersionUID, it will be calculated. And, as documented in the javadoc of Serializable, the calculated value is extremely sensitive and it is thus recommended be explicitly declare it to avoid any deserialization problems. And this is what Eclipse is "complaining" about (note that this is just a warning).
您的情况的“问题”是HashMap实现Serializable. 此接口没有任何方法,仅用于标识 be serializable 的语义。换句话说,它是一个标记接口,您实际上不必实现任何东西。但是,在反序列化过程中,Java 使用称为 a 的版本号serialVersionUID来验证序列化版本是否与目标兼容。如果您不提供 this serialVersionUID,它将被计算。而且,如 的 javadoc 中Serializable所述,计算出的值非常敏感,因此建议明确声明它以避免任何反序列化问题。这就是 Eclipse 所“抱怨”的(请注意,这只是一个警告)。
So, to avoid this warning, you could add a serialVersionUIDto your annonymous inner class:
所以,为了避免这个警告,你可以serialVersionUID在你的匿名内部类中添加一个:
someMethodThatTakesAHashMap(new HashMap<String, String>() {
private static final long serialVersionUID = -1113582265865921787L;
{
put("a", "value-a");
put("c", "value-c");
}
});
But you loose the conciseness of the syntax (and you may not even need it).
但是你失去了语法的简洁性(你甚至可能不需要它)。
Another option would thus be to ignore the warning by adding a @SuppressWarnings("serial")to the method where you are calling someMethodThatTakesAHashMap(Map). This seems more appropriate in your case.
因此,另一种选择是通过将 a 添加@SuppressWarnings("serial")到您正在调用的方法来忽略警告someMethodThatTakesAHashMap(Map)。这似乎更适合您的情况。
That all being said, while this syntax is concise, it has some drawbacks. First, if you hold a reference on the object initialized using a double-brace initialization, you implicitly hold a reference to the outer object which won't be eligible for garbage collection. So be careful. Second (this sounds like micro optimization though), double-brace initialization has a very a little bit of overhead. Third, this technique actually uses anonymous inner classes as we saw and thus eats a bit of permgen space (but I doubt that this is really a problem unless you reallyabuse them). Finally - and this is maybe the most important point - I am not sure it makes the code more readable (it's not a well known syntax).
话虽如此,虽然这种语法很简洁,但它也有一些缺点。首先,如果您持有对使用双括号初始化初始化的对象的引用,则您隐式持有对外部对象的引用,该对象将不符合垃圾收集条件。所以要小心。其次(虽然这听起来像微优化),双括号初始化有一点点开销。第三,正如我们所见,这种技术实际上使用了匿名内部类,因此会占用一些永久空间(但我怀疑这是否真的是一个问题,除非你真的滥用它们)。最后 - 这可能是最重要的一点 - 我不确定它是否使代码更具可读性(它不是众所周知的语法)。
So, while I like to use it in tests (for the conciseness), I tend to avoid using it in "regular" code.
因此,虽然我喜欢在测试中使用它(为了简洁),但我倾向于避免在“常规”代码中使用它。
回答by Bart Kiers
Yes, you could suppress the warning, but I'd rewrite it like this:
是的,您可以取消警告,但我会像这样重写它:
HashMap<String, String> map = new HashMap<String, String>();
map.put("a","value-a");
map.put("c","value-c");
someMethodThatTakesAHashMap(map);
No suppressing needed, and much better to read, IMO.
IMO 无需压制,阅读效果也更好。
回答by T.R.
I generally agree with Bart K., but for informational purposes:
The warning can also be eliminated by adding the field, which can be automatically generated by hitting ctrl+1.
The warning can also be suppressed by adding the @SuppressWarnings("serial") annotation before the definition.
The anonymous class implements Serializeable, and Serializeable requires this static field so that versions can be distinguished when serializing and de-serializing. More information here:
http://www.javablogging.com/what-is-serialversionuid/
我大体上同意 Bart K.,但仅供参考:
也可以通过添加字段来消除警告,该字段可以通过按 ctrl+1 自动生成。
也可以通过在定义前添加 @SuppressWarnings("serial") 注释来抑制警告。
匿名类实现了Serializeable,Serializeable 需要这个静态字段,以便在序列化和反序列化时区分版本。更多信息在这里:http:
//www.javablogging.com/what-is-serialversionuid/
回答by finnw
The ImmutableMapclass from the Google Collections library is useful for this situation. e.g.
ImmutableMapGoogle Collections 库中的类在这种情况下很有用。例如
someMethodThatTakesAHashMap(ImmutableMap.<K, V>builder().put("a","value-a").put("c","value-c").build());
or
或者
someMethodThatTakesAHashMap(ImmutableMap.of("a","value-a","c","value-c"));
回答by Sean Owen
To address the other half of your question, "should I suppress it?" --
回答你问题的另一半,“我应该压制它吗?” ——
Yes. In my opinion, this is a terrible warning. serialVersionUID should by default notbe used, not the other way around.
是的。在我看来,这是一个可怕的警告。默认情况下不应使用serialVersionUID,反之亦然。
If you don't add serialVersionUID, the worst thing that happens is that two versions of an object that are actually serialization-compatible are deemed incompatible. serialVersionUID is a way to declare that the serialization compatibility has not changed, overriding Java's default assessment.
如果不添加serialVersionUID,最糟糕的情况是,实际上序列化兼容的对象的两个版本被认为不兼容。serialVersionUID 是一种声明序列化兼容性没有改变的方法,覆盖 Java 的默认评估。
Using serialVersionUID, the worst thing that happens is that you inadvertently fail to update the ID when the class's serialized form changes in an incompatible way. At best, you also get a runtime error. At worst, something worse happens. And imagine how easy it is to fail to update it.
使用serialVersionUID,发生的最糟糕的事情是当类的序列化形式以不兼容的方式更改时,您无意中未能更新ID。充其量,您还会收到运行时错误。在最坏的情况下,会发生更糟糕的事情。并想象一下无法更新它是多么容易。
回答by rickmode
Your intent was to initialize an anonymous instance of HashMap. The warning is clue that your code is doing more than you intended.
您的意图是初始化 HashMap 的匿名实例。警告提示您的代码做得比您预期的要多。
What we're looking for is a way to initialize an anonymous HashMap instance. What we have above creates an anonymous subclass of HashMap then creates an anonymous instance of that anonymous class.
我们正在寻找的是一种初始化匿名 HashMap 实例的方法。我们上面的内容创建了 HashMap 的匿名子类,然后创建了该匿名类的匿名实例。
Because the code does more than was intended, I'd call it a hack.
因为代码的作用超出了预期,我将其称为 hack。
What we really want is something like this:
我们真正想要的是这样的:
foo(new HashMap<String, String>({"a", "value-a"}, {"c", "value-c"}));
But alas this isn't valid Java. There isn't a way to do anything this in a type-safe way using an array of key/value pairs. Java simple doesn't have the expressive power.
但可惜这不是有效的 Java。没有办法使用键/值对数组以类型安全的方式执行任何操作。Java simple 没有表现力。
The Google Collection's ImmutableMap.of static methods are close but it means creating a version of the factory method for various numbers of key/value pairs. (See finnw's answer.)
Google Collection 的 ImmutableMap.of 静态方法很接近,但这意味着为各种数量的键/值对创建工厂方法的版本。(见 finnw 的回答。)
So keep things simple. Go with Bart K's solution unless your code is littered with this initialization. If so use ImmutableMap. Or roll your own HashMap subclass with the "of" style factory methods. Or create these "of" style factory methods in a utility class. Here's one for two key/value pairs:
所以保持简单。使用 Bart K 的解决方案,除非您的代码充满了这种初始化。如果是这样,请使用 ImmutableMap。或者使用“of”样式工厂方法滚动您自己的 HashMap 子类。或者在实用程序类中创建这些“of”风格的工厂方法。这是两个键/值对之一:
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;
}
}
Embrace the verbosity and take solace in the knowledge your corporate co-workers are wearing the same shackles as you.
拥抱冗长,并从你的公司同事和你一样戴着同样枷锁的知识中得到安慰。

