A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

近来发现很多马友提了很多关于序列化的问题,于是我也赶紧收集资料补充一把,可很多知识点还是云山雾罩。查阅JDK文档,接口 Serializable下,发现有一个serialVersionUID 版本号的东西,这是个什么东西?它在实际中有什么作用呢?
[ 本帖最后由 张小明 于 2011-07-24  03:44 编辑 ]

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2 精神可嘉!

查看全部评分

5 个回复

倒序浏览
黑马网友  发表于 2011-7-24 05:52:16
沙发
当你一个类实现了Serializable接口,如果没有定义serialVersionUID,Eclipse会提供这个
     提示功能告诉你去定义 。如果你没有考虑到兼容性可以把它关掉,不管怎样Eclipse都会给你warning提示,这个serialVersionUID为了让该类别Serializable向后兼容。

它的作用是序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。即是保持兼容性。

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2 希望你的答案能帮助到他!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-24 09:33:23
藤椅
在进行对象序列化和反序列化的时候,对于不同JDK版本,会出现版本兼容问题。
  |-  如:在JDK1.5序列化的对象,在JDK1.0上面可能就不能使用了。
  |-  为了解决对象的序列化和反序列化间的版本不统一问题,引入了一个类常量。
       |-  static final long serialVersionUID
      |-  在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应的类的SerialVersionUID比较
       |-  如果相同 则就认为版本一致 因此可以进行反序列化。
       |-  如果不相同 则就认为版本不一致 然后就抛[color=Red]“序列化版本不一致”[/color]异常。

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2 答到边了的都有分!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-24 14:07:43
板凳
1、Serializable是一个标志性接口,没有任何成员变量和方法。需要序列化一个类时只需要声明实现这个接口即可。
2、如果类A中组合了类B的对象的化,序列化类A对象的同时会序列化类B对象,前提是类A和类B都实现了Serializable接口。
3、如果类B继承类A,那么序列化类B分为下面两中情况:
    1)类A没有实现Serializable接口,而类B实现了。那么根据JavaAPI中的说明,如果需要序列化类B,需要保证类A和类B都有无参的构造方法,如果无法默认构造,则必须显式声明。没有无参构造方法的话,在运行时会报异常。 用这种方式试了一下,虽然可以序列化类A继承来的属性(public、protected、包访问),但是不能正确读取,读出来是null,类B自身特有的属性没问题。有待进一步验证。
    2)类A实现了Serializable接口(类B实不实现无所谓,因为继承类A)。通过类B给继承于类A的变量和自身特有的变量赋值,并进行序列化。序列化成功,并可以正确读取。
    serialVersionUID用于可序列化类的版本控制。如果不显式的声明一个serialVersionUID,JVM会基于这个序列化类的不同方面特征自动生成一个。

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2 答到边了的都有分!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-24 14:17:57
报纸
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
       如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2 答到边了的都有分!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-24 15:30:26
地板
Java 规定的内部机制,实现 Serializable 接口就行了,这个接口只是个标记性的接口,表示类的设计者已经允许这个类型的对象被序列化写入磁盘或通过网络发送,对于有保密要求的东西一般不实现这个接口防止无意间复制到 jvm 内存之外。如果一个类型的多数字段可以复制但个别字段不用复制(比如,它实际上是通过其它字段计算出来的),我们可以把它标记为 transient。
    默认的 serialization 对类的结构有要求,一般将来版本升级了导致服务端和客户版本不一样,或者你用新版本读取一个以前旧版本写入磁盘的序列化的对象的话,需要这两个版本是兼容的,达到这个要求至少包括下面这个字段,并且新旧两个版本的类中它的值应该是一样的,其它特殊情况规范也有办法做到,比如你的结构变了,以前 name / phone 都是 A 的字段,后来新版本创建了一个内部类叫 Contact 把 name 和 phone  
并到这两个字段移到内部类 Contact 中去了的话,Java 也有办法在新版本中提供自定义 readObject/writeObject 这个过程来确保兼容旧版本。

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马