在这个问题上有一堆误解.
在Java中实现Serializable接口时,我需要创建一个静态的最终长序列版本UID.
不,你不知道.试一试--go 编写一个类,在上面加上implements Serializable
,do not加上serialVersionUID
,然后用普通的javac编译它.您会发现[A]编译得很好,[B]也不会生成任何警告.
各种LinterTool(添加额外代码清洁度判断的工具)错误地抱怨必须添加该字段.有时该字段是必需的,但在网络上通常不应该添加它.
那块地到底是做什么用的?
只有当您try 使用类的版本A进行序列化,然后在版本B位于类路径上时将其反序列化时,该字段才会出现.(B与A不同,事实上,B与A的签名非常不同).
This is extremely tricky-当Person类以前有String name
个,现在有PersonName name
个,因为名字现在被分成首字母、合作伙伴名称、昵称等,这意味着什么?您不能只添加一些serialVersionUID
,然后祈祷Java序列化机制知道该做什么.
正因为如此,默认情况下,序列化机制将完全拒绝反序列化为已更改的类(它更改了签名:添加/移除了一个字段或方法,或重命名了现有的方法/字段,或更改了字段的擦除类型,或更改了方法获得/丢失的参数,或其参数之一的擦除类型已更改).
This is correct--几乎总是不能‘只是’反序列化成一个像那样改变的版本,而且几乎总是需要手动注意(使用readObject
和类似的机制来控制序列化机制).
设置serialVersionUID
是向Java反序列化机制指示的机制:实际上,只需反序列化到这个新版本;将任何新引入的字段保留为null / 0 / '\0' / false
-并忽略新版本中不再存在的旧字段的任何值.
不需要这块地
所有类都有一个序列版本UID,无论您是否有该字段.具有显式SVU字段的类将其视为SVU,而其他类具有其计算出的SVU.您可以使用java
和javac
可执行文件旁边的serialver
工具轻松地看到这些.
做这件事的正确方法
If(极不可能!)你需要在两个不同的版本之间进行序列化/反序列化,and(更不可能!)你可以通过让反序列化程序尽最大努力而"逍遥法外",然后是write some test code that confirms this(毕竟,如果失败,你的应用程序将被 destruct ),这意味着你必须仍然拥有旧版本的类.所以,只需serialver
个,然后将这个连续版本粘贴到新版本中.
That is the one and only circumstance a class should EVER have a 100 field.
地平线上将出现更多问题
Java的串行化机制并不是特别好.它的API充满了奇怪的 struct 化类型(除了main
和agentmain
之外,在Java中没有其他语言可以做到这一点),并且除了JVM之外,其他任何人都无法读取该格式.在这个微服务和网络连接的现代世界里,这是非常有限的.因此,序列化(如在Java中烘焙的东西)是not recommended.即使是OpenJDK团队本身也倾向于淡化它,或者直接建议不要使用它.
相反,可以将其序列化为JSON或使用protobuf.这些格式在许多平台上都是可读的,并且使序列化行为变得明确.
修好你的短绒布
不管是什么告诉你‘哦,不!你有一个实现了Serializable的类(通常,不是故意的,比如Exception
实现了它,因此所有的子类型都实现了,但是你很少序列化异常),你必须添加一个SerialVersionUID字段!-修复它.关闭那个警告.
不管这些,我只想强迫实现者有一些域
这在Java中几乎是不可能的.接口cannot要求一个子类有一个字段,static
个成员不以任何方式‘做’层次 struct ,并且您不能重写字段.在多种从基础到Java语言的方法中,‘强制使用子类型来添加字段’的概念是完全没有意义的.这不仅仅是"不可能",它甚至没有任何意义.