Java学习笔记(十三)--序列化、反序列化与无参构造函数

概念

  1. 序列化:将对象保存到磁盘中,或允许在网络中直接传输对象,对象序列化机制允许把内存中的Java对象转换成平台无关的二进制,从而可以持久的保存在磁盘上,也可以在网络中传输。
  2. 反序列化:程序一旦获得了序列化的对象,则这种二进制流都可以恢复成原来的

如何实现序列化

    1.Serializable

要序列化的对象,实现该接口,无需重写任何方法

    2.Externalizable

要序列化的对象实现该接口,并且需要实现writeExternal和readExternal方法

简单对象的序列化

 1.单一的对象序列化

  • 创建一个Person类

public class Person implements Serializable{
    private String id;

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

   注意:1.Person类实现了Serializable接口

           2.该实体类没有提供无参构造函数

  •  写一个测试类,测试一下序列化与反序列化      

try {
            //序列化
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("2.txt"));
            Person person = new Person("111");
            objectOutputStream.writeObject(person);
            //反序列化
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("2.txt"));
            Person person1 = (Person) objectInputStream.readObject();
            System.out.println(person1.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

  •    执行结果


  •   Person类去掉实现序列化接口(即,将public class Person implements Serializable修改为public class Person),重新执行


    结论:简单类型(无继承关系)对象序列化时必须实现序列化接口,有无无参构造函数都key

2.存在继承关系,但并无引用关系的对象序列化

  • 创建Student类,继承Person类
public class Student extends Person implements Serializable{
    private int no;

    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                '}';
    }

    public Student(String id ,int no) {
        super(id);
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

}
  • Person类对象既没实现序列化接口,又没有提供无参构造函数
public class Person{
    private String id;

//    public Person() {
//    }

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  • 执行序列化与反序列化

  • 另Person对象实现序列化接口,再次执行,结果成功
public class Person implements Serializable{
    private String id;

//    public Person() {
//    }

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  • 不实现序列化接口,提供无参构造函数,执行结果成功
public class Person {
    private String id;

    public Person() {
    }

    public Person(String id) {
        System.out.println("youcacn");
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
  结论:存在继承关系时,若想序列化子类对象,一并序列化父类对象,则负责类型必须实现序列化接口或者提供无参构造函数

对象引用的序列化

  •     Student类继承Person类,并有对象引用关系
public class Student extends Person implements Serializable {
    private int no;
    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }
        
    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                '}';
    }

    public Student(String id, int no) {
        super(id);
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

}
  • 一个demo序列化Student实例与反序列化Student实例
try {
            //序列化
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("2.txt"));
            Person person = new Person("111");
            Student stuB = new Student("B", 163);
            stuB.setPerson(person);
            objectOutputStream.writeObject(stuB);
            //反序列化
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("2.txt"));
            Student student  = (Student) objectInputStream.readObject();
            System.out.println(student.getPerson());
        } catch (Exception e) {
            e.printStackTrace();
        }
  • Person类不实现序列化接口,也不提供无参构造函数,执行结果如下:

  • Person类不实现序列化接口,提供无参构造函数,执行结果如下:


  • Person类实现序列化接口,但不提供无参构造函数,执行结果如下:


结论

  1. 单一对象,无继承关系:若想实现序列化与反序列化,则必须实现序列化接口,否则报异常:NotSerializableException
  2. 对象间有继承关系,但无引用关系,若想实现序列化与反序列化,则父类必须实现序列化接口或提供无参构造函数,否则报invalidClassException
  3. 对象间有继承关系,并且有引用关系,若想实现序列化与反序列化,则父类必须实现序列化接口

猜你喜欢

转载自blog.csdn.net/zh15732621679/article/details/79803105