Java 基础 —— 序列化
一、什么是序列化Java 提供了一种对象序列化的机制,该机制中,一个对象可以被按字节进行持久化(被表示为一个字节序列),该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息和对象的数据,还有对象中的数据类型可以用来在内存中新建对象。序列化与反序列化都是 Java 虚拟机(JVM)独立
一、什么是序列化
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被按字节进行持久化(被表示为一个字节序列),该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息和对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
序列化与反序列化都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象
。
二、为什么要序列化
我们的 Java 对象不只是存储在内存中,它还需要在传输网络中进行传输,或者保存在文件中下次再加载出来,这时候就需要序列化技术。
数据是对象,而不是文本。 现在的问题是网络和硬盘可以理解位和字节但不能理解 Java 对象的硬件组件。 因此需要将 Java 对象的值/状态转换为字节,以便通过网络发送或保存在硬盘。反序列化是将字节码转换为相应的 Java 对象。
1)一般 Java 对象的生命周期比 Java 虚拟机短,而实际开发中如果需要 JVM 停止后能够继续持有对象,则需要用到序列化技术将对象持久化到磁盘或数据库。
2)在多个项目进行 RPC 调用时,需要在网络上传输 JavaBean 对象,而网络上只允许二进制形式的数据进行传输,这时则需要用到序列化技术。
Java 的序列化技术就是把对象转换成一串由二进制字节组成的数组,然后将这二进制数据保存在磁盘或传输网络
。而后需要用到这对象时,磁盘或者网络接收者可以通过反序列化得到此对象
,达到对象持久化的目的。
三、怎么序列化
类 ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法。
1)ObjectInputStream 类的 writeObject() 方法将传入的 obj 对象进行序列化,把得到的字节序列写入到目标输出流中进行输出。
2)ObjectOutputStream 类中的 readObject() 方法从输入流中读取字节序列,然后将字节序列反序列化为一个对象并返回。它的返回值为 Object,因此,你需要将它转换成合适的数据类型
。
1、序列化的要求
一个类的对象要想序列化成功,必须满足两个条件:
1)
该类必须实现 java.io.Serializable 接口
。
2)该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的
。
2、serialVersionUID
SerialVersionUID 用于对象的版本控制,确保在反序列化期间加载相同的对象
(在序列化期间使用的对象)。如果序列化和反序列化的类版本不一致,则在反序列化的时候就会报错。
3、标注非序列化属性
(1)transient 关键字
1)
对象属性一旦被 transient 修饰,则不再是对象持久化的一部分了,而且变量内容在反序列化时也不能获得
。在序列化时,如果我们不想序列化特定变量以满足安全约束,那么我们应该将该变量声明为 transient。执行序列化时,JVM 会忽略 transient 变量的原始值并将默认值保存到文件中
。因此,transient意味着不要序列化。
2)transient 修饰符仅适用于变量,不适用于方法和类
。而且本地变量是不能被 transient 修饰的。
3)如果对象属性是类变量,则需要该类变量也实现 Serializable 接口
。
4)final 变量将直接通过值参与序列化,所以将 final 变量声明为 transient 变量不会产生任何影响。(2)static 关键字
静态变量不是对象状态的一部分,因此它不参与序列化
。所以一个静态变量不管是否被 transient 修饰,都不会被序列化。
四、复杂情况下的序列化
1、序列化对象引用其他对象
如果一个序列化对象引用了其他对象,
该序列化对象所引用的对象都会被序列化,因此被引用的对象类也必须实现 serialzable 接口
。
2、序列化中的继承
(1)如果超类(父类)是可序列化的
如果超类是可序列化的,则其所有子类都可以自动序列化
。即父类实现了 Serializable,子类不需要实现 Serializable。
(2)如果超类不可序列化
如果父类未实现 Serializable 而子类实现了,则在序列化子类实例的时候,父类的属性会被跳过不保存
。
如何实现未实现 Serializable 接口的父类的属性也被序列化:1)
父类必须有一个无参的 constructor
;
2)父类还必须有一个有参的 constructor,而且在子类中显示调用父类的有参构造函
数:super(args…)。
(3)如果超类可序列化但您不希望子类可序列化
如果您不希望子类可序列化,则需要实现 writeObject()和readObject()方法,并且需要从此方法中抛出 NotSerializableException。
四、示例
更多推荐
所有评论(0)