1 基本概念
-
对象序列化是一个用于将对象状态转换为字节流的过程。
可以将其保存到磁盘文件或者通过网络发送到其他程序。 -
反序列化,从字节流创建对象的过程
创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。
2 使用原因
在java中,我们可以通过多种方式来创建对象,并且只要对象没有被收回,我们都可以复用此对象。
但是,我们创建出来的这些对象都存在于JVM的堆(stack)内存中,只有JVM处于运行状态的时候,这些对象才可能存在。一旦JVM停止,这些对象将随之消失。
但是在真实的场景中,我们需要将这些对象持久化下来,并且在需要的时候将对象重新读出来。
Java的序列化可以帮我们实现这个功能。
3 应用场景
- 当想把内存中的对象状态保存到一个文件中或者数据库中的时候
- 当想用套接字在网络上传送对象的时候
- 当想用RMI(远程方法调用)传输对象的时候
4 序列化条件?
- 通过java.Io.Serialization接口启用序列化功能
未实现此类接口的类将无法将其任何状态或者信息进行序列化和反序列化 - 一个类要想序列化成功,必须满足两个条件:
(1)该类必须实现Java.io.Serialiable对象
(2)该类所有属性必须是可序列化的,如果有一个属性不可序列化,则该属性必须注明是短暂的。
5 如何进行序列化?
-
如果一个类实现了Serialzable接口,该类如何实现序列化和反序列化?
-
Java.Io包为我们提供了ObjectInputStream和ObjectOutputStream,他们是最高层次的数据流,他们包含序列化和反序列化对象的方法。
(1)Java.Io.ObjectInputStream类实现类的序列化功能
(2)Java.Io.ObjectOutputStream类实现类的反序列化功能 -
序列化实例:
import java.io.*;
import java.util.Date;
public class ObjectSaver {
public static void main(String[] args) throws Exception {
/*其中的 /Users/slq/Desktop/java/4/objectFile.obj 表示存放序列化对象的文件*/
//序列化对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/slq/Desktop/java/4/objectFile.obj"));
Customer customer = new Customer("王麻子", 24);
out.writeObject("你好!"); //写入字面值常量
out.writeObject(new Date()); //写入匿名Date对象
out.writeObject(customer); //写入customer对象
out.close();
//反序列化对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/slq/Desktop/java/4/objectFile.obj"));
System.out.println("obj1 " + (String) in.readObject()); //读取字面值常量
System.out.println("obj2 " + (Date) in.readObject()); //读取匿名Date对象
Customer obj3 = (Customer) in.readObject(); //读取customer对象
System.out.println("obj3 " + obj3);
in.close();
}
}
class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "name=" + name + ", age=" + age;
}
}
6 不想对某个字段进行序列化怎么办?
这时候就要用到transient关键字,当某字段被transient关键字声明后,默认序列化机制就会忽略该字段。
7 如果序列化内容有更改,能否成功序列化?
答案是肯定不能的,会抛出Java.io.InvalidClasssException异常,从异常信息可以看出,它是根据SerialVersionUid值来进行判断类是否修改过。
- 如果 添加新字段后,还想继续加载以前的字段怎么办?
- 在类中添加SerialVersionUid属性字段,当SerialVersionUid的值和报错信息中的SerialVersionUid的值一样就可以正常序列化。
8 SerialVersionUid从哪来?
- 如果类中没有显示声明SerialVrersionUid属性,那么java编译器会自动为我们生成一个SerialVersionUid,应该是根据属性和方法进行摘要算出来的,方法里的内容改动SerialVersionUid不会变。
- 如果对象升级版本,修改了结构,而且不兼容以前的版本,只需要修改下SerialVersionUid的值就可以了。