序列化及SerialVersionUID困扰着许多Java开发人员。我经常会看到这样的问题,什么是SerialVersionUID,如果实现了Serializable接口的类中没有定义SerialVersionUID的话会怎样?抛开它的复杂性以及不太常用不说,一个原因就是Eclipse在缺少了SerialVersionUID之后的给出的警告提示:"The Serializable class Customer does not declare a static final SerialVersionUID field of type long”。从本文中你可以了解到SerialVersionUID的基础知识以及它在序列化及反序列化中所起到的作用。当你通过实现java.io.Serializable接口将一个类声明为可序列化的,并且你没有通过 Externalizable接口自定义自己的序列化方式的话,Java会在运行时使用默认的序列化机制将这个类持久化到磁盘里面。在序列化的过程中,Java会在运行时为这个类生成一个版本号,这样它后面才可以进行反序列化。这个版本号就是SerialVersionUID。如果在反序列化的过程中,SerialVersionUID不匹配的话,这个反序列化的过程就会失败,同时会抛出java.io.InvalidClassException异常,并打印出类的名字以及对应的SerialVersionUID。一个快速的解决办法就是在你的类中声明一个private static final long类型的SerialVersionUID常量。本文中你将了解到为什么要使用SerialVersionUID,以及如何使用JDK工具serialver来生成这个ID。如果你从未了解过序列化的话,你可以看下这篇
Java序列化的十个面试题来检验下你的相关知识,看看往下读的话理解起来有没有难度。和并发以及多线程类似,序列化是另一个值得反复阅读的主题。
Java中为什么使用SerialVersionUID
我刚才也说过了,如果你的类里没有声明一个static, final并且是long类型的SerialVersionUID属性的话,Java的序列化机制会替你生成一个的。它的生成机制受很多因素的影响,包括类中的字段,还有访问限制符,类实现的接口,甚至是不同的编译器实现,任何类的修改或者使用了不同的编译器生成的SerialVersionUID都各不相同,很可能最终导致重新加载序列化的数据中止。依赖Java的序列化机制来生成这个ID的话太危险了,这就是为什么推荐你在需要序列化的类中自己声明一个SerialVersionUID的原因。我强烈推荐你读一下Joshua Bloch的Java经典著作,_Effective Java_ 来了解下Java的序列化机制以及错误的处理所导致的问题。顺便提一句,JDK提供了一个叫serailver的工具,它在JAVA_HOME文件夹下的bin目录 里,在我的机器上是:C:\Program Files\Java\jdk1.6.0_26\bin\serialver.exe,你可以用它来为老的class文件来生成SerialVersionUID。如果你修改了你的类,破坏了序列化的过程从而导致你的应用程序无法重新加载序列化的数据的时候,这个工具就非常有用了。你可以用这个工具来为老的实例重新生成SerialVersionUID,然后通过在你的类中声明一个static final long类型的SerialVersionUID来显式地指定它。同时,不管是出于性能还是安全的原因,都强烈推荐使用自定义的二进制格式进行序列化,Effective Java里也曾多次提到了这点,里面对自定义格式的好处有详细的介绍。
如何使用JDK工具serialver来生成SerialVersionUID
你可以使用JDK的serialver来生成类的SerialVersionUID。这个对于现有的类来说尤其有用,它返回的SerialVersionUID很适用复制使用。你可以像下例中这样使用serialver:
$ serialver use: serialver [-classpath classpath] [-show] [classname…]
$ serialver -classpath . Hello Class Hello is not Serializable.
$ serialver -classpath . Hello Hello: static final long SerialVersionUID = -4862926644813433707L;
你还可以通过运行$serialver -show来以GUI的形式来使用serailver工具,这会打开一个序列化版本号的查看器,它接收完整的类名并输出对应的序列化版本号。
总结
现在我们已经知道什么是SerialVersionUID以及为什么在类中声明SerialVersionUID是如此重要了,可以回顾下一些相关的重要的概念了。
1. SerialVersionUID是用于序列化数据的。只有当序列化的实例的SerialVersionUID和当前类的匹配才能进行反序列化。
2. 如果你不在类中声明SerialVersionUID的话,Java会在运行时替你生成一个,不过这个生成的过程会受到类元数据包括字段数,字段类型,字段的访问限制符,类实现的接口等因素的影响。在Oralce的官方文档中你可以找到关于序列化的准确的描述信息。
3. 推荐自己声明privae static final long类型的SerialVersionUID字段来避免默认机制。如果你没这么做的话,像Eclipse的一些IDE会提示警告信息:"The Serializable class Customer does not declare a static final SerialVersionUID field of type long"。尽管你可以通过Window > Preferences > Java > Compiler > Errors / Warnings > Potential Programming Problems
将这个功能屏蔽掉,但我建议你还是不要这么做。我见过的唯一例外的情况就是不需要恢复数据的情况下。下面是在Eclipse IDE中这个错误的截图,你需要做的就是点击一下快速修复。
4. 你可以使用JDK提供的serailver工具来给Java类生成序列版本号。它也有一个GUI界面,可以通过传递-show参数启用它。
5. Java序列化的最佳实践就是显式地声明SerialVersionUID,避免反序列化过程中可能出现的问题,尤其是当你运行的C/S模式的应用依赖于RMI进行数据序列化的时候。
这就是Java中SerialVersionUID 的全部内容。现在我们知道在类中声明SerialVersionUID 的重要性了。感谢你的IDE给了你这个提示,不然你的类反序列化的时候可能就会出现问题了。
如果你想了解下关于序列化相关的更多的一些知识,可以参考下下面几篇不错的文章:
Java中transient和volatile变量的区别
Java中Serializable和Externalizable接口的不同
Java中何时应该使用transient变量
原创文章转载请注明出处:
http://it.deepinmind.com
英文原文链接
分享到:
相关推荐
Java 中 serialVersionUID 的解释 Java 中的 serialVersionUID 是一个非常重要的概念,在实现 Serializable 接口的类中,它扮演着至关重要的角色。那么,serialVersionUID到底是什么?它又是如何生成的?在本篇文章...
在Java编程中,`serialVersionUID` 是一个非常重要的概念,特别是在序列化和反序列化过程中。这个特殊标识符主要用于版本控制,确保不同版本的类在序列化和反序列化时能够正确匹配。当我们讨论`serialVersionUID`时...
### Java 类中 `serialVersionUID` 详解 #### 一、`serialVersionUID` 概述 在 Java 中,`serialVersionUID` 是一个与类关联的长整型常量,用于支持序列化机制。当一个对象被序列化时,该对象所属类的 `...
Java类中serialVersionUID的作用及其使用 Java类中serialVersionUID是一种特殊的静态变量,用于标识类的序列化版本。它是Java语言中实现Serializable接口的类必须定义的变量,用于在反序列化时验证类的版本一致性。...
在 Java 序列化机制中,serialVersionUID 是一个不可或缺的角色,它可以通过在运行时判断类的 serialVersionUID 来验证版本一致性。在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID 与本地相应实体...
Java中的`serialVersionUID`是一个非常重要的概念,尤其是在处理序列化和反序列化操作时。序列化是将对象的状态转换为字节流的过程,而反序列化则是将字节流恢复为对象状态。`serialVersionUID`的主要作用是确保在类...
`serialVersionUID`在Java序列化过程中起着关键作用。 首先,让我们来理解什么是IO流。IO流是Java中处理数据输入和输出的一种机制。Java提供了一整套类库来支持不同类型的流,包括字符流和字节流,它们分别处理文本...
Java 序列化和 serialVersionUID 的使用...Java 序列化和 serialVersionUID 是 Java 中非常重要的概念,它们用于实现对象的持久化和网络传输。正确使用 serialVersionUID 可以确保版本的兼容性,避免反序列化时的异常。
如果两个不同版本的类具有相同的`serialVersionUID`,那么在反序列化过程中可能会出现`InvalidClassException`异常,这是因为Java序列化机制认为这两个版本是不兼容的。 #### 五、`serialVersionUID`的定义 `...
在 Java 中,当一个类实现了java.io.Serializable接口时,编译器会提示一个黄色的警告,因为该类没有提供 serialVersionUID 字段。serialVersionUID 是一个私有静态常量,用于标识类的版本号。在序列化和反序列化...
序列化版本号serialVersionUID的作用_动力节点Java学院整理.
三期第一张IO笔记 6
为了避免序列化过程中出现`java.io.InvalidClassException`异常,特别是处理序列化对象版本兼容性问题时,强烈推荐在所有可序列化的类中显式声明`serialVersionUID`。这不仅可以提高程序的稳定性和健壮性,还能简化...
关键代码位于`java.io.ObjectStreamClass#initNonProxy`方法中,该方法会比较类的serialVersionUID以判断是否匹配。 为了绕过这个检查,我们可以尝试破坏以下三个条件之一: 1. 本地和远程类是否都实现了...
serialVersionUID 是 Java 序列化机制中一个非常重要的概念,它是 Java 序列化机制的核心组件。 serialVersionUID 是一个长整型常量,用于标识类的版本号。在 Java 序列化机制中,serialVersionUID.play 一个非常...
在Java编程中,自定义事件是扩展应用程序功能和实现组件间通信的重要手段。当你需要在类之间传递特定信息或触发特定行为时,自定义事件能提供极大的灵活性。本教程将深入探讨如何在Java中创建并使用自定义事件,以...
本文详细介绍了Spark中的五个经典转换算子的Java实现,包括Map、FlatMap、Filter、MapPartitions和Distinct。这些算子在实际项目中被广泛使用,可以帮助开发者高效地处理大规模数据。此外,文章还提供了每个算子的...
本章节主要讲解Java的序列化机制,包括Serializable接口、Externalizable接口、transient关键字、serialVersionUID变量等。 Java学习系列(十三):Java面向对象之界面编程 本章节主要讲解Java的界面编程,包括AWT...
在给定的链接"Java序列化机制(2)- serialVersionUID 实验"中,博主通过一个实验详细解释了`serialVersionUID`的作用和重要性。实验可能包括以下步骤: 1. 创建一个实现`Serializable`接口的简单类,并运行序列化...
Java 中使用 List 遇到黄色警告图标如何去除 Java 中使用 List 时出现黄色警告图标的原因是由于没有使用泛型,导致编译器无法确定 List 中保存的对象类型。解决方法是使用泛型,例如 `List<String> list = new ...