Java序列化


Java序列化

序列化的含义、意义以及使用场景

  • 序列化:将对象写入到IO流中
  • 反序列化:从IO流中恢复对象
  • 意义:序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。
  • 使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。

普通序列化

Serializable接口是一个标记接口,不用实现任何方法。一旦实现了此接口,该类的对象就是可序列化的。

序列化步骤

  • 步骤一:创建一个ObjectOutputStream输出流;

  • 步骤二:调用ObjectOutputStream对象的writeObject输出可序列化对象。

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "Person{" + "name=" + this.name + ",age=" + this.age + "}";
    }
}

public class JavaDemo {
    public static void main(String[] args) {
        try {
            ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("object.txt"));
            Person person = new Person("Aike", 20);
            System.out.println(person.toString());
//            将对象序列化到文件中
            oos.writeObject(person);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

反序列化步骤
步骤一:创建一个ObjectInputStream输入流;

步骤二:调用ObjectInputStream对象的readObject()得到序列化的对象。

import java.io.*;

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        System.out.println("反序列化调用(检测反序列化是否调用了构造函数)");
        this.name = name;
        this.age = age;
    }
    
//      存在无参构造函数将会报错
//    public Person() {
//        System.out.println("反序列化调用(检测反序列化是否调用了构造函数)");
//    }

    public String toString() {
        return "Person{" + "name=" + this.name + ",age=" + this.age + "}";
    }
}

public class JavaDemo {
    public static void main(String[] args) {
        try {
//            创建一个ObjectInputStream流
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
            Person brady = (Person) ois.readObject();
            System.out.println(brady.toString());
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

反序列化并不会调用构造方法。反序列的对象是由JVM自己生成的对象,不通过构造方法生成。

成员是引用的序列化

如果一个可序列化的类的成员不是基本类型,也不是String类型,那这个引用类型也必须是可序列化的,否则会导致此类不能序列化。

import java.io.*;

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Teacher implements Serializable {
    private String name;
    Person person;

    public Teacher(String name, Person person) {
        this.name = name;
        this.person = person;
    }
}

public class JavaDemo {
    public static void main(String[] args) {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"));
            Person person = new Person("孙悟空", 9999);
            Teacher teacher = new Teacher("唐三藏", person);
            oos.writeObject(teacher);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
java.io.NotSerializableException: Person

程序报错的原因是Person类的对象是不可序列化的,这导致了Teacher对象不可序列化。

同一对象序列化多次的机制

import java.io.*;

class Person implements  Serializable{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String toString() {
        return "Person{" + "name=" + this.name + ",age=" + this.age + "}";
    }
}

class Teacher implements Serializable {
    private String name;
    Person person;

    public Teacher(String name, Person person) {
        this.name = name;
        this.person = person;
    }

    public String toString(){
        return "Teacher{"+"name="+this.name+this.person.toString()+"}";
    }
}

public class JavaDemo {
    public static void main(String[] args) {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"));
            Person person = new Person("孙悟空", 9999);
            Teacher t1 = new Teacher("唐三藏", person);
            Teacher t2 = new Teacher("菩提祖师", person);
            oos.writeObject(t1);
            oos.writeObject(t2);
            System.out.println(t1.toString());
            System.out.println(t2.toString());
            System.out.println("-----------------------------------");
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream("teacher.txt"));
            Teacher t_1=(Teacher)ois.readObject();
            Teacher t_2=(Teacher)ois.readObject();
            System.out.println(t_1.toString());
            System.out.println(t_2.toString());
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

从输出结果可以看出,Java序列化同一对象,并不会将此对象序列化多次得到多个对象。

Java序列化算法

  1. 所有保存到磁盘的对象都有一个序列化编码号

  2. 当程序试图序列化一个对象时,会先检查此对象是否已经序列化过,只有此对象从未(在此虚拟机)被序列化过,才会将此对象序列化为字节序列输出。

  3. 如果此对象已经序列化过,则直接输出编号即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值