在网络通信中,任何数据都是以二进制的形式来传输的。对象序列化可以把内存中的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异常。