在网络通信中,任何数据都是以二进制的形式来传输的。对象序列化可以把内存中的Java对象转成二进制流,而二进制流可以存放在本地磁盘文件中,通过网络或程序来获取该二进制流后,就能将该二进制流恢复成Java对象。序列化的这一过程就是将对象状态信息转换为可存储或传输的过程。
对象序列化的作用:
- 对象序列化可以把对象以字节序列的形式永久保存在磁盘中。
- 对象序列化可以用于在网络中传输对象。
- 对象序列化使得对象可以脱离程序的运行而独立存在。
序列化与反序列化
序列化是将一个Java对象写入IO流中,转换成字节序列,而反序列化是用IO流将字节序列恢复成Java对象。要实现对象序列化,该对象的类必须实现接口Serializable,该接口没任何方法,仅作标记,说明该类可以实现序列化。
若序列化对象的成员变量是一个引用类型,则该引用类型变量的类也要实现Serializable接口,保证序列化过程中用到的类都要实现序列化,不然会出现异常。
对象序列化步骤:
- 使用ObjectOuputStream,使用writeObject()将一个对象序列化。也就是将对象转成二进制流,存放在磁盘文件中,实现持久化。
public class Person implements Serializable{
private String name;
private int age;
private String sex;
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}/**省略setter 和 getter*/
}
//把对象写入序列化文件,完成对象序列化
public class Test {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("D:\\Object01.txt");//存放对象字节序列的文件路径
//对象输出流中的节点流是一个缓冲流,该流包装节点流,所以需要flush()
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos));
Person p = new Person("张三", 15, "男");
oos.writeObject(p);
oos.flush();
}
}
对象反序列化步骤
调用ObjectInputStream的readObject()方法读取序列化文件中的二进制流,转成对象
FileInputStream fis = new FileInputStream("D:\\Object01.txt");
//创建一个ObjectInputStream输入流,节点流数据源是一个对象序列化文件
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
//读取Person对象
Person p = (Person)ois.readObject();
System.out.println(p.getName() + "||" + p.getAge() +"||" + p.getSex());
使用反序列化的注意点
- 反序列化将二进制流数据转成对象,所以在此之前要保证该类存在,不然Java对象没有存在意义。
- 如果读取的序列化文件中存在多个对象,则必须按照他们序列化的顺序来读取,不然会出错。
- 如果成员变量使用transient修饰,那么反序列化后,该成员变量数据没有。
- 反序列化的对象没有使用构造器来初始化。
测试序列化多个对象:
public class Person implements Serializable{
private String name;
private int age;
private transient String sex; //透明化,表示该成员变量不会序列化
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
/** 省略getter 和 setter */
}
public class Test {
public static void main(String[] args) throws Exception {
//存放对象字节序列的文件路径
FileOutputStream fos = new FileOutputStream("D:\\MoreObject.txt");
//对节点流使用了缓冲流,所以需要flush()
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos));
Person p = new Person("张三", 15, "男");
Person p1 = new Person("李四", 20, "男");
Person p2 = new Person("王五", 25, "男");
//序列化多个对象
oos.writeObject(p);
oos.writeObject(p1);
oos.writeObject(p2);
oos.flush();
//创建一个对象输入流ObjectInputStream
FileInputStream fis = new FileInputStream("D:\\MoreObject.txt");
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
//恢复多个对象
Person per1 = (Person) ois.readObject();
Person per2 = (Person) ois.readObject();
Person per3 = (Person) ois.readObject();
// Person per4 = (Person) ois.readObject(); //EOFException
System.out.println(per1.getName() + "||" + per1.getAge() +"||" + per1.getSex());
System.out.println(per2.getName() + "||" + per2.getAge() +"||" + per2.getSex());
System.out.println(per3.getName() + "||" + per3.getAge() +"||" + per3.getSex());
// 输出结果:
// 张三||15||null
// 李四||20||null
// 王五||25||null
}
}
- 实例说明:
- 被transient修饰的成员变量sex,无法对数据序列化,所以输出结果中是null,因为该值是引用类型,如果是值类型就是系统默认的初始值。
- 恢复的对象顺序是和序列化对象一致的,这是因为反序列化文件有多个对象,恢复的顺序也是按照对象序列化时的顺序来恢复的。
- 如果序列化文件中的对象已经读取完了,再次readObject()会引发EOFException异常。