`
danwind
  • 浏览: 233929 次
  • 性别: Icon_minigender_1
  • 来自: 广东
社区版块
存档分类
最新评论

关于Serializable的serialVersionUID

    博客分类:
  • Java
阅读更多

众所周知,当某class实现了Serializable接口后,由此class构建出的对象将具备序列化的能力,而Serializable这个接口中没有任何需要实现的方法,所以这个接口的作用仅仅是作为一个标记,告诉虚拟机,具有这个标记的对象,是可以被序列化的,而没有这个标记的则不要序列化。所以,虚拟机应该是可以将任何对象序列化的,只不过是它遵守了一个“道德“规范,仅序列化那些被允许可以序列化的。那为什么不是所有的对象都是可序列化的呢?我想也许是基于安全性的考量吧。

序列化的一般过程是:

  1. 在虚拟机A中,构造了class AClass的对象AObject
  2. 将AObject序列化写入到文件ObjectFile中
  3. 在虚拟机B中,读取文件ObjectFile
  4. 根据AClass和读取进来的byte[],构造虚拟机B中的AClass的对象BObject

这里面,不好理解的事情是在第四步中,如果虚拟机B仅有AObject的数据,并不足以构造出BObject,它必须还需要有AClass的信息。也就是说, 序列化,仅仅是把对象以二进制的形式写入到了文件之中,但是这些二进制该组织成什么样的一个东西,却并不能说明,所以还需要AClass的类型信息,这就 如同交给了你一大堆的机器零件,还需要你拥有一本组装说明书,你才能把这些零件组装成一架波音747。:)。也就是说,序列化的仅仅是Object,而没有同时把这个Object所依赖的所有class一并序列化过去。那为什么不这么做呢?也许和ClassLoader有关?又和安全性有关?

在实现了Serializable接口的class中,需要声明一个long serialVersionUID,用来标明当前class的版本号:

  • 如果在序列化时的版本号和序列化时的版本号,不一致,将会有异常:
    java.io.InvalidClassException:
    local class incompatible: stream classdesc serialVersionUID = …, local class serialVersionUID = …
  • 那如果在class中不声明这个属性呢?那结果可以就会变得比较诡异了:
    • 在序列化的时候,虚拟机A会为它计算出一个serialVersionUID,计算的方法是依据class的信息,再具体我也不清楚了。
    • 在序列化的时候,虚拟机B也会为class计算出一个serialVersionUID,然后做比较。
    • 那么如果两个虚拟机是不同类型的虚拟机,那么计算方法可能就不一样了,于是即使相同的class,serialVersionUID也可能会不同,不同的class的,理论上来说,也存在serialVersionUID相同的可能性,所以,serialVersionUID尽量由我们自己来指定,而不要由虚拟机来计算。
  • 那如果serialVersionUID一致,而class发生了变化呢?
    • 如果虚拟机A中的AClass有一个属性,而虚拟机B中的AClass,没有这个属性,那么这个属性将被忽略,而不会有异常。
    • 如果虚拟机A中的AClass没有的属性,而在虚拟机B中多出来的属性,那么这个属性将被赋予一个缺省值,而不会有异常。
    • 如果虚拟机A中的AClass有一个属性,在虚拟机B中的AClass也有这个属性,但这个属性的类型变了,比如说int变成了long,抑或其他的变化,将会有异常:
      java.io.InvalidClassException:
      incompatible types for field …

经过序列化而产生的异常都是 java.io.InvalidClassException,不会产生java.lang.ClassCastException,两者还是有比较大的区别的,从名字上就可以看得出来。

 

 

 

我自己遇到的问题是:local class incompatible: stream classdesc serialVersionUID = 4379444343007238900, local class serialVersionUID = -4347374884104808421
 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)

解决办法是去除所有Eclipse自动生成的serialVersionUID,当去除所有的serialVersionUID 后还出现以上问题,重启tomcat就好了

分享到:
评论

相关推荐

    Java中serialVersionUID的解释

    Java 中的 serialVersionUID 是一个非常重要的概念,在实现 Serializable 接口的类中,它扮演着至关重要的角色。那么,serialVersionUID到底是什么?它又是如何生成的?在本篇文章中,我们将详细地解释 ...

    详述IntelliJ IDEA 中自动生成 serialVersionUID 的方法(图文)

    在安装 GenerateSerialVersionUID 插件后,可以在 Inspections 设置页面中勾选 Serializable class without 'serialVersionUID',并且还可以在 Severity 中设置提示级别,如 Warning、Error 等,默认为 Warning。...

    序列化 serializable demo

    例如,`MySerializable.java`和`Product.java`两个文件可能分别代表实现了`Serializable`接口的类。`MySerializable`可能是自定义的一个示例类,而`Product`可能是表示产品的类,它们都包含了可序列化的属性。 在`...

    java类中serialVersionUID详解.pdf

    当实现 `java.io.Serializable` 接口的类未明确声明 `serialVersionUID` 时,Java 序列化机制将根据编译后的 Class 文件自动生成一个 `serialVersionUID`。此规则下,即使多次重新编译,只要 Class 文件内容不变...

    可序列化接口Serializable

    在Java编程语言中,`Serializable`接口是一个非常重要的概念,它是实现对象持久化的关键。本文将深入探讨`Serializable`接口的细节,以及与其相关的高级知识。 `Serializable`接口是Java中的一个标记接口,没有包含...

    coreJava: serialVersionUID

    在Java编程中,`serialVersionUID` 是一个非常重要的概念,特别是在序列化和反序列化过程中。这个特殊标识符主要用于版本控制,确保不同版本的类在序列化和反序列化时能够正确匹配。当我们讨论`serialVersionUID`时...

    Serializable java序列号

    在Java中,如果一个类需要支持序列化,那么该类需要实现`java.io.Serializable`接口,虽然这个接口没有定义任何方法,但是它的存在作为一个标记,表明该类的对象可以被序列化。 序列化的优点主要有以下几点: 1. **...

    Java对象Serializable接口实现详解

    在实现Serializable接口时,需要注意的是必须提供一个固定的serialVersionUID变量,这个变量用于标识该类的版本号,以便在反序列化时可以正确地还原对象。例如,在上面的例子中,我们定义了一个User类,并实现了...

    Serializable-master.zip

    《深入理解Java序列化:serialVersionUID与序列化过程解析》 在Java编程中,序列化是一种将对象的状态转换为字节流的过程,以便可以存储在磁盘上或在网络上传输。这一过程对于实现持久化、跨网络通信以及分布式计算...

    析Android中的Serializable序列化.rar_Serializable _android

    3. 版本兼容性:当类结构发生变化时(如添加、删除或修改字段),需要考虑序列化版本号(serialVersionUID)以保持序列化数据的兼容性。如果没有显式声明,Java会自动生成一个版本号,但更改类结构可能导致反序列化...

    java.io.Serializable序列化问题

    - **版本兼容性**:序列化的类应该定义一个 `serialVersionUID` 来确保版本兼容性。 - **私有构造函数**:如果类有私有的构造函数,需要提供一个无参的公共构造函数,否则反序列化会失败。 - **安全性**:对于敏感...

    serialVersionUID作用全面解析

    在实现 Serializable 接口的类中,如果没有显示地定义 serialVersionUID,Java 序列化机制会根据编译的 Class 自动生成一个 serialVersionUID 作序列化版本比较用。 在实际应用中,serialVersionUID 的应用场景非常...

    java serializable 序列化与反序列化

    `Serializable`接口是Java提供的一个标记接口,用于实现对象的序列化。当一个类实现了这个接口,它的实例就可以被序列化。 **一、Java序列化** 1. **什么是序列化**:序列化是将对象的状态(属性和成员变量)转换...

    java类中serialVersionUID的作用及其使用

    serialVersionUID是Java语言中实现Serializable接口的类必须定义的变量,用于在反序列化时验证类的版本一致性。它是实现类持久化的重要组件,使得类可以被序列化和反序列化,从而实现了类的持久化。 在实际应用中,...

    序列化类的作用Serializable

    实现`Serializable`接口,配合使用特殊序列化方法,以及妥善管理`serialVersionUID`,可以有效地控制和优化对象的序列化过程。这对于数据持久化、网络通信以及分布式系统中的对象交换都有着至关重要的作用。

    idea如何自动生成serialVersionUID

    在IDEA的Default Settings中,进入Inspections设置页面中,勾选Serializable class without 'serialVersionUID',并且还可以在Severity中设置提示级别,如Warning、Error等,默认为Warning,也建议选择Warning级别的...

    java序列化(Serializable)的作用和反序列化.doc

    private static final long serialVersionUID = 1L; private int width; private int height; private String name; public void setWidth(int width) { this.width = width; } public void setHeight(int...

    java序列化(Serializable)的作用和反序列化

    private static final long serialVersionUID = 1L; private int width; private int height; private String name; public static void main(String[] args) { try { Box myBox = new Box(); myBox....

    Java序列化(Serializable)与反序列化_.docx

    ### Java序列化(Serializable)与反序列化详解 #### 序列化概念与应用场景 序列化是指将程序中的对象转换为一系列字节序列的过程,主要用于保存对象的状态以便将来使用或者在网络之间传输对象。Java提供了内置的...

    使用SerializableDemo

    标题"使用SerializableDemo"表明这是一个关于如何使用`Serializable`接口的实际示例或教程。通过提供的链接(http://www.cnblogs.com/xubuhang/p/4500479.html),我们可以预期会深入探讨`Serializable`接口的用法,...

Global site tag (gtag.js) - Google Analytics