一、概述

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化:
image.png

二、ObjectOutputStream

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

构造方法

  • public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。

构造举例,代码如下:
FileOutputStream fileOut = new FileOutputStream(“employee.txt”);
ObjectOutputStream out = new ObjectOutputStream(fileOut);

序列化操作

  1. 一个对象要想序列化,必须满足两个条件:
  • 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。

    1. public class Employee implements java.io.Serializable {
    2. public String name;
    3. public String address;
    4. public transient int age; // transient瞬态修饰成员,不会被序列化
    5. public void addressCheck() {
    6. System.out.println("Address check : " + name + " -- " + address);
    7. }
    8. }

    2.写出对象方法

  • public final void writeObject (Object obj) : 将指定的对象写出。

    1. public class SerializeDemo{
    2. public static void main(String [] args) {
    3. Employee e = new Employee();
    4. e.name = "zhangsan";
    5. e.address = "beiqinglu";
    6. e.age = 20;
    7. try {
    8. // 创建序列化流对象
    9. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
    10. // 写出对象
    11. out.writeObject(e);
    12. // 释放资源
    13. out.close();
    14. fileOut.close();
    15. System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年龄没有被序列化。
    16. } catch(IOException i) {
    17. i.printStackTrace();
    18. }
    19. }
    20. }
    21. 输出结果:
    22. Serialized data is saved

    三、ObjectInputStream

    ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

    构造方法

  • public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。

    反序列化

    1. public class DeserializeDemo {
    2. public static void main(String [] args) {
    3. Employee e = null;
    4. try {
    5. // 创建反序列化流
    6. FileInputStream fileIn = new FileInputStream("employee.txt");
    7. ObjectInputStream in = new ObjectInputStream(fileIn);
    8. // 读取一个对象
    9. e = (Employee) in.readObject();
    10. // 释放资源
    11. in.close();
    12. fileIn.close();
    13. }catch(IOException i) {
    14. // 捕获其他异常
    15. i.printStackTrace();
    16. return;
    17. }catch(ClassNotFoundException c) {
    18. // 捕获类找不到异常
    19. System.out.println("Employee class not found");
    20. c.printStackTrace();
    21. return;
    22. }
    23. // 无异常,直接打印输出
    24. System.out.println("Name: " + e.name); // zhangsan
    25. System.out.println("Address: " + e.address); // beiqinglu
    26. System.out.println("age: " + e.age); // 0
    27. }
    28. }

    1、对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。
    2、另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。原因一般如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配

  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法