usr*_*ΛΩΝ 15 java serialization
在可能需要修改可序列化类并保持向后兼容性的情况下,我有一个关于Java序列化的问题.
我来自深入的C#经验,所以请允许我将Java与.NET进行比较.
在我的Java场景中,我需要使用Java的运行时序列化机制序列化对象,并将二进制数据存储在永久存储中以便将来重用这些对象.问题是,将来,课程可能会发生变化.可以添加或删除字段.
我不太了解Java序列化,除了这篇关于如何在处理序列化时不用Java编程的精彩文章.正如我想象的那样(d),serialVersionUID在Java序列化中起着关键作用,这就是我需要你帮助的地方.
除了文章的例子(我知道它的编码很糟糕),当我在修改类之后要求更新它时,该字段是否应该被修改?
我记得在.NET世界中,当我添加新字段时,我必须将[OptionalField]属性添加到字段以获得向后兼容性,因此CLR不会在旧的序列化数据中要求它.此外,当我需要弃用字段时,我必须只删除公共方法而不是私有字段.
最佳序列化的准则是什么?
谢谢.
[添加]这是一个例子.假设我有Foo课
public class Foo {
private String bar;
}
Run Code Online (Sandbox Code Playgroud)
然后我改为:
public class Foo {
private String bar;
private Integer eggs;
}
Run Code Online (Sandbox Code Playgroud)
这两个版本之间的兼容性是否破裂?如果我在编译"newFoo"时反序列化"oldFoo",那么egg会等于null还是抛出异常?我更喜欢第一个,显然!!
Cra*_*lin 11
假设您有一个类,MyClass并且您希望确保序列化兼容性,或者至少确保您不会无意中更改其序列化形式.您可以使用Verify.assertSerializedForm()从GS集合测试实用程序在大多数情况下.
通过编写一个测试,声称你的类有一个启动serialVersionUID的0L,具有串行形式是空字符串.
@Test
public void serialized_form()
{
Verify.assertSerializedForm(
0L,
"",
new MyClass());
}
Run Code Online (Sandbox Code Playgroud)
运行测试.它将失败,因为String表示Base64编码并且永远不会为空.
org.junit.ComparisonFailure: Serialization was broken. <Click to see difference>
Run Code Online (Sandbox Code Playgroud)
当您单击以查看差异时,您将看到实际的Base64编码.将其粘贴到空字符串中.
@Test
public void serialized_form()
{
Verify.assertSerializedForm(
0L,
"rO0ABXNyAC9jYXJhbWVsa2F0YS5zaHVrbmlfZ29lbHZhLkV4ZXJjaXNlOVRlc3QkTXlDbGFzc56U\n"
+ "hVp0q+1aAgAAeHA=",
new MyClass());
}
Run Code Online (Sandbox Code Playgroud)
重新运行测试.它可能会再次失败并显示如下错误消息.
java.lang.AssertionError: serialVersionUID's differ expected:<0> but was:<-7019839295612785318>
Run Code Online (Sandbox Code Playgroud)
将新的serialVersionUID粘贴到测试中代替0L.
@Test
public void serialized_form()
{
Verify.assertSerializedForm(
-7019839295612785318L,
"rO0ABXNyAC9jYXJhbWVsa2F0YS5zaHVrbmlfZ29lbHZhLkV4ZXJjaXNlOVRlc3QkTXlDbGFzc56U\n"
+ "hVp0q+1aAgAAeHA=",
new MyClass());
}
Run Code Online (Sandbox Code Playgroud)
现在测试将通过,直到您更改序列化表单.如果您意外中断测试(更改序列化表单),首先要做的是检查您是否serialVerionUID在Serializable类中指定了它.如果你把它留下来,JVM会为你生成它并且非常脆弱.
public class MyClass implements Serializable
{
private static final long serialVersionUID = -7019839295612785318L;
}
Run Code Online (Sandbox Code Playgroud)
如果测试仍然中断,您可以尝试通过将新字段标记为瞬态来恢复序列化表单,使用writeObject()等完全控制序列化表单.
如果测试仍然中断,您必须决定是否查找并还原您的更改,这些更改会导致序列化或将更改视为对序列化表单的有意更改.
当您有意更改序列化表单时,您需要更新Base64字符串以使测试通过.当你这样做时,同时改变它是至关重要的serialVersionUID.你选择的数字并不重要,只要它是你以前从未用过的数字.惯例是将其更改为2L,然后3L等.如果您从随机生成serialVersionUID(如-7019839295612785318L示例中)开始,您仍应该将数字添加到2L因为它仍然是序列化表单的第二个版本.
注意:我是GS系列的开发人员.
| 归档时间: |
|
| 查看次数: |
10040 次 |
| 最近记录: |