欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

I/O流--序列化流与反序列化流

程序员文章站 2022-07-09 23:06:50
...

什么是序列化流与反序列化流
用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流(把看不懂的乱码转化成看得懂的)
用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流(把看得懂的以乱码的形式写到文件中)
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。
ObjectOutputStream

I/O流--序列化流与反序列化流

I/O流--序列化流与反序列化流
构造方法中的参数代表要写入的文件,也就是你将要把看得懂的转化成看不懂的乱码写入到哪个路径下
上代码:

FileOutputStream fos = new FileOutputStream("t.tmp");
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        oos.writeInt(12345);
        oos.writeObject("Today");
        oos.writeObject(new Date());

        oos.close();

ObjectInputStream
I/O流--序列化流与反序列化流
I/O流--序列化流与反序列化流
构造方法中的参数代表要读取的文件,也就是你将要从这个路径下的文件把看不懂的转化成看得懂的读取到内存中
上代码:

 FileInputStream fis = new FileInputStream("t.tmp");
        ObjectInputStream ois = new ObjectInputStream(fis);

        int i = ois.readInt();
        String today = (String) ois.readObject();
        Date date = (Date) ois.readObject();

        ois.close();

序列化对象
Person类

public class Person implements Serializable {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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 + "]";
}

}
对于细心人可以看出,该bean实现了Serializable 接口,没错,如果想要序列换一个对象,那么首先就是要把对象类实现这个接口。不然报错,发生异常NotSerializableException异常,实现后就可以了。

注意:
同时当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException。发生这个异常的原因如下:
1.该类的序列版本号与从流中读取的类描述符的版本号不匹配
2.该类包含未知数据类型
3.该类没有可访问的无参数构造方法
Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
代码修改如下

public class Person implements Serializable {
    //给类显示声明一个序列版本号。
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public Person() {
        super();

    }
    public Person(String name, int age) {
        super();
        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 + "]";
    }
}

说白了,就是添加一个serialVersionUID 值,就这个东西,只要他保持一直,就不会报错了

瞬态关键字transient
在这里要提一下一个关键字–transient
用途:
当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会被序列化了。
同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
栗如:

public class Person implements Serializable {
    /*
     * 给类显示声明一个序列版本号。
     */
    private static final long serialVersionUID = 1L;
    private static String name;
    private transient/*瞬态*/ int age;

    public Person() {
        super();

    }

    public Person(String name, int age) {
        super();
        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 + "]";
    }
}

总结:
所谓的序列化就是把本来看得懂的转化成看不懂的,给你存储起来,有加密的作用。
反序列化就是把之前序列化的文件反转为序列化之前的文件,有解密作用。