序列化与反序列化

概述

序列化

把对象以流的方式写到文件中保存,叫写对象的序列化

对象中包含的不仅仅是字符,还有字节

ObjectOutputStram:对象序列化流

反序列化

把文件中保存的对象以流的方式读取出来,叫做读对象,也叫反序列化

读取的文件保存的都是字节流

ObjectInputStream:对象的反序列化流

ObjectOutputStream

构造方法

protected ObjectOutputStream(); :为了完全实现ObjectOutputStream的子类提供一种方法,让它不必分配仅由ObjectOuputStream的实现使用的私有数据.

ObjectOutputStream(OutputStream); :创建写入指定的OutputStream的OutputStream

Serializable接口也叫标记型接口,要进行序列化和反序列化的类必须实现serializable接口,就会给类添加一个标记,当我们进行序列化和反序列化的时候会检测类上是否有这个标记,有就可以序列化和反序列化,没有就会跑出异常

Pserson类

import java.io.Serializable;

//实现这个接口,才能够进行序列化和反序列化
//不然会抛出java.io.NotSerializableException
public class Person implements Serializable {
    private String name;
    private int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

main.java

import java.io.*;

public class Main {

    public static void main(String[] args) throws IOException {
        //创建ObjectOutputStream对象,构造方法中传递字节输出流
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(".\\person.txt"));
        //使用ObjectOutputStreeam对象中的方法writeObject把对象写入到文件中
        oos.writeObject(new Person("姓名",18));
        oos.close();
    }
}

ObjectInputStream

构造方法

protected ObjectInputStream(); :为完全重新实现ObjectInputStream的子类提供一种方式,让它不必分配仅由ObjectInputStream的实现使用的私有数据

ObjectInputStream(InputStream in); :创建从指定的InputStream读取的ObjectInputStream

反序列化必须要存在对应的class文件

Main.java

import java.io.*;

public class Main {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //创建ObjectInputStream对象,构造方法中传递字节输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(".\\person.txt"));
        //使用ObjectInputStream对象中的方法readObject读取保存对象的文件
        // readObject还抛出了ClassNotFoundException异常,当不存在class文件的时候会抛出异常
        Object o=ois.readObject();///可以强转
        //释放资源
        ois.close();
        //打印对象
        System.out.println(o);//Person{name='姓名', age=18}
    }
}

transient

static关键字

静态优先于费静态加载到内存中

当jvm吧字节码加载到虚拟机当中,static他修饰的成员会自动的加载到内存当中(方法区),static优先于对象的存在,并且被所有的对象共享

transient

瞬态关键字

如果给了成员变量加上这个这个关键字,就不会参与序列化和反序列化

InvalidClassException

当jvm饭序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么操作也会失败,抛出一个InvaildClassExption异常原因如下

  • 该类的序列版本号从流中读取的类描述的版本号不匹配
  • 该类包含为止数据类型
  • 该类没有可访问的无参构造方法

编译器,会把Person.java文件编译成Person.class文件.PErson类实现了Serializable接口,就会根据类的定义给Person.class文件添加一个序列号

serialversionUID

当修改了类的定义,name就会给Person.class文件重新生成一个新的序列号

反序列化的时候,会使用Person.class文件中的序列号和Person.txt文件中的序列化号进行比较,如果是一样的则反序列化成功,如果不也一样则抛出序列化冲突异常InvaildClassException

问题:每次修改类的定义,都会给class文件生成一个新的编号

解决方案:无论是否对类的定义进行修改,都不重新生成序列号,可以手动各给类添加一个序列号

static final long serialversionUID=42L;
Last modification:April 21, 2022
如果觉得我的文章对你有用,请随意赞赏