众所周知,当某class实现了Serializable接口后,由此class构建出的对象将具备序列化的能力,而Serializable 这个接口中没有任何需要实现的方法,所以这个接口的作用仅仅是作为一个标记,告诉虚拟机,具有这个标记的对象,是可以被序列化的,而没有这个标记的则不要 序列化。所以,虚拟机应该是可以将任何对象序列化的,只不过是它遵守了一个“道德“规范,仅序列化那些被允许可以序列化的。那为什么不是所有的对象都是可 序列化的呢?我想也许是基于安全性的考量吧。
序列化的一般过程是:
- 在虚拟机A中,构造了class AClass的对象AObject
- 将AObject序列化写入到文件ObjectFile中
- 在虚拟机B中,读取文件ObjectFile
- 根据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,两者还是有比较大的区别的,从名字上就可以看得出来。
相关推荐
Java 中的 serialVersionUID 是一个非常重要的概念,在实现 Serializable 接口的类中,它扮演着至关重要的角色。那么,serialVersionUID到底是什么?它又是如何生成的?在本篇文章中,我们将详细地解释 ...
IntelliJ IDEA 自动生成 serialVersionUID 在 Java 序列化机制中,...IntelliJ IDEA 自动生成 serialVersionUID 是一个非常有用的功能,它可以帮助开发者更方便地实现序列化和反序列化,提高开发效率和质量。
综上所述,`serialVersionUID` 在 Java 的序列化机制中扮演着关键角色,它不仅能够确保序列化数据的一致性和完整性,还能够在类结构发生变化时帮助开发者有效管理版本兼容性问题。理解并正确使用 `serialVersionUID`...
例如,`MySerializable.java`和`Product.java`两个文件可能分别代表实现了`Serializable`接口的类。`MySerializable`可能是自定义的一个示例类,而`Product`可能是表示产品的类,它们都包含了可序列化的属性。 在`...
在Java编程中,`serialVersionUID` 是一个非常重要的概念,特别是在序列化和反序列化过程中。这个特殊标识符主要用于版本控制,确保不同版本的类在序列化和反序列化时能够正确匹配。当我们讨论`serialVersionUID`时...
`Serializable`接口在Java中扮演着至关重要的角色,它提供了对象持久化和网络传输的能力。理解并熟练掌握序列化机制,可以帮助开发者在实际项目中解决各种问题,提升代码的可维护性和安全性。通过阅读《Java_序列化...
在Java中,如果一个类需要支持序列化,那么该类需要实现`java.io.Serializable`接口,虽然这个接口没有定义任何方法,但是它的存在作为一个标记,表明该类的对象可以被序列化。 序列化的优点主要有以下几点: 1. **...
序列化的核心接口是 `java.io.Serializable`,它是一个标记接口,没有定义任何方法,用于标记可以被序列化的类。 #### 二、实现序列化的方法 为了使一个类支持序列化,需要让该类实现 `Serializable` 接口。实现这...
Java对象Serializable接口实现详解 Java中的Serializable接口是java.io包中定义的,...Serializable接口是Java中一个非常重要的接口,它使得Java对象可以被序列化和反序列化,从而实现了对象的持久化存储和网络传输。
虽然Serializable是常用的序列化方式,但在Android中,还有其他序列化库,如Parcelable接口,它的序列化和反序列化效率更高,更适合Android环境。另外,Gson、Jackson、protobuf等第三方库也是不错的选择,它们提供...
下面是一个简单的例子,演示了如何使用 Serializable 接口和 serialVersionUID 实现序列化和反序列化: ```java package com.sxit; import java.io.File; import java.io.FileInputStream; import java.io....
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....
例如,对于一个`Box`对象,如果它有`width`和`height`两个实例变量,序列化时会保存这两个变量的值。 2. **元数据的保存**:除了实例变量的状态外,序列化还会记录一些元数据,如对象所属的类名、版本号等,以便在反...
Java的序列化与反序列化是Java开发中的一项重要技术,它允许我们将对象的状态转换为字节流,以便存储或在网络上传输。`Serializable`接口是Java提供的一个标记接口,用于实现对象的序列化。当一个类实现了这个接口,...
`serialVersionUID` 是Java序列化机制中的一个关键元素,它是一个长整型字段,用于版本控制。当一个类被序列化时,Java会根据类的结构(如字段、方法等)生成一个唯一的`serialVersionUID`。如果在反序列化时,目标...
4. **实现Serializable并提供serialVersionUID**:确保类的序列化兼容性,避免因类结构变化导致的反序列化失败。 **七、实战应用** 在实际项目中,例如在网络通信中传递复杂对象,或者是将对象持久化到数据库或文件...
序列化接口`Serializable`的实现类需要一个`serialVersionUID`字段,它是一个长期不变的标识符,用于识别特定版本的类。当一个类被序列化时,JVM会将该类的`serialVersionUID`与存储的序列化数据中的`...
serialVersionUID 是 Java 序列化机制中一个非常重要的概念,它是 Java 序列化机制的核心组件。 serialVersionUID 是一个长整型常量,用于标识类的版本号。在 Java 序列化机制中,serialVersionUID.play 一个非常...
3. 实现类的持久化:serialVersionUID是实现类持久化的重要组件,它使得类可以被序列化和反序列化,从而实现了类的持久化。 serialVersionUID的使用: 1. 显式定义serialVersionUID:可以显式地定义...
实现`Serializable`接口,配合使用特殊序列化方法,以及妥善管理`serialVersionUID`,可以有效地控制和优化对象的序列化过程。这对于数据持久化、网络通信以及分布式系统中的对象交换都有着至关重要的作用。