Java基础回顾-序列化流

序列化流

概述

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


ObjectOutputStream:对象的序列化流

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

构造方法

public objectoutputStream(OutputStream out):创建一个指定OutputStream的ObjectOutputStream.

参数

​ outputstream out:字节输出流

特有的成员方法

​ void writeObject(0bject obj)将指定的对象写入、0bjectoutputstreamo

使用步骤

​ 1.创建Objectoutputstream对象,构造方法中传递字节输出流
​ 2.使用Objectoutputstream对象中的方法writeobject,把对象写入到文件中
​ 3.释放资源

序列化操作的前提

一个对象要想序列化,必须满足两个条件:

  1. 该类必须实现java.io.Serializable接口,Serializable是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
  2. 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient关键字修饰。
import java.io.Serializable;
/*
    序列化和反序列化的时候,会抛出NotSerializableExceptioni没有序列化异常

    类通过实现java.io.Serializable接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。

    serializabLe接口也叫标记型接口

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

        去市场买肉-->肉上有一个蓝色章(检测合格)-->放心购买-->买回来怎么吃随意

    static关键字:静态关键字
    静态优先于非静态加载到内存中(静态优先于对象进入到内存中)被static修饰的成员变量不能被序列化的,序列化的都是对象
    private static int age;
    oos. iwriteobject( new Student(18,'牛牛'));
    object o = ois .readObject();
    Student {age=0,'牛牛'}
    
    transient关键字:瞬态关键字
    被transient修饰成员变量,不能被序列化
    private trgnsient int age;
    oos.wwriteObject(new Student(18,"牛牛”));
    Object o = ois.readObject();
    Student {age=0,'牛牛'}
 */
public class Student implements Serializable {//要进行序列化和反序列化的类必须实现Serializable接口
    private int age;
    private String name;

    public Student() {
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/*
    java.io.0bjectoutputstream extends outputstreamobjectoutputstream:对象的序列化流
    作用:把对象以流的方式写入到文件中保存

    构造方法:
        objectoutputStream(OutputStream out)创建写入指定OutputStream的 objectOutputStreamo

    参数:
        outputstream out:字节输出流

    特有的成员方法:
        void writeObject(0bject obj)将指定的对象写入、0bjectoutputstreamo

    使用步骤:
        1.创建Objectoutputstream对象,构造方法中传递字节输出流
        2.使用Objectoutputstream对象中的方法writeobject,把对象写入到文件中
        3.释放资源

 */
public class DemosObjectOutputStream {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("FileAndIO\\src\\main\\java\\abc.txt\\student.txt"));
        oos.writeObject(new Student(18,"牛牛"));
        oos.close();
    }

}

ObjectInputStream :对象的反序列化流

java.io.ObjectInputstream extends InputStream
作用:把文件中保存的对象,以流的方式读取出来使用

构造方法

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

参数

InputStream in :字节输入流

特有的成员方法

Object readobject()从ObjectInputStream读取对象。

使用步骤

1.创建ObjectInputStream对象,构造方法中传递字节输入流
2.使用ObjectInputstream对象中的方法readobject读取保存对象的文件
3.释放资源
4.使用读取出来的对象(打印)

readobject方法声明抛出了CLassNotFoundException(class文件找不到异常)当不存在对象的class文件时抛出此异常

反序列化操作的前提

1.类必须实现SeriaLizable
2.必须存在类对应的cLass文件

import java.io.*;

/*
java.io.ObjectInputstream extends InputStream
ObjectInputStream :对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用

构造方法:
ObjectInputStream(InputStream in)创建从指定InputStream 读取的ObjectInputStream

参数:
InputStream in :字节输入流

特有的成员方法:
Object readobject()从ObjectInputStream读取对象。

使用步骤:
1.创建ObjectInputStream对象,构造方法中传递字节输入流
2.使用ObjectInputstream对象中的方法readobject读取保存对象的文件
3.释放资源
4.使用读取出来的对象(打印)

readobject方法声明抛出了CLassNotFoundException(class文件找不到异常)当不存在对象的class文件时抛出此异常

反序列化的前提:
1.类必须实现SeriaLizable
2.必须存在类对应的cLass文件
 */
public class DemosObjectInputStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("FileAndIO\\src\\main\\java\\abc.txt\\student.txt"));
        Object o = ois.readObject();
        ois.close();
        System.out.println(o);
        Student s = (Student) o;
        System.out.println(s.getAge()+s.getName());
    }

}


对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个classNotFoundException异常。

反序列化操作2

另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个 InvalidclassException异常。发生这个异常的原因如下:

  1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  2. 该类包含未知数据类型
  3. 该类没有可访问的无参数构造方法

Serializable接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

自定义序列号

import java.io.Serializable;
/*
    序列化和反序列化的时候,会抛出NotSerializableExceptioni没有序列化异常

    类通过实现java.io.Serializable接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。

    serializabLe接口也叫标记型接口

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

        去市场买肉-->肉上有一个蓝色章(检测合格)-->放心购买-->买回来怎么吃随意

    static关键字:静态关键字
    静态优先于非静态加载到内存中(静态优先于对象进入到内存中)被static修饰的成员变量不能被序列化的,序列化的都是对象
    private static int age;
    oos. iwriteobject( new Student(18,'牛牛'));
    object o = ois .readObject();
    Student {age=0,'牛牛'}

    transient关键字:瞬态关键字
    被transient修饰成员变量,不能被序列化
    private trgnsient int age;
    oos.wwriteObject(new Student(18,"牛牛”));
    Object o = ois.readObject();
    Student {age=0,'牛牛'}
 */
public class Student implements Serializable {//要进行序列化和反序列化的类必须实现Serializable接口
    private static final long serialVersionUID = 546547;//自定义序列号
    private int age;
    private String name;

    public Student() {
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

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

练习:序列化集合

import java.io.*;
import java.util.ArrayList;

/*
    练习:序列化集合
        当我们想在文件中保存多个对象的时候可以把多个对象存储到一个集合中对集合进序列化和反序列化
    分析:
        1.定义一个存储Student对象的ArrayList集合
        2.往ArrayList集合中存储Student对象
        3.创建一个序列化流ObjectOutputStream对象
        4.使用ObjectOutputStream对象中的方法writeObject,对集合进行序列化
        5.创建一个反序列化ObjectInputStream对象
        6.使用ObjectInputStream对象中的方法reodObject读取文件中保存的集合
        7.把Object类型的集合转换为ArrayList类型
        8.遍历ArrayList集合
        9.释放资源
 */
public class DemosSerializationTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student(18,"牛牛1"));
        list.add(new Student(19,"牛牛2"));
        list.add(new Student(20,"牛牛3"));
        list.add(new Student(21,"牛牛4"));
        list.add(new Student(22,"牛牛5"));
        list.add(new Student(23,"牛牛6"));

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("FileAndIO\\src\\main\\java\\abc.txt\\student1.txt"));
        oos.writeObject(list);
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("FileAndIO\\src\\main\\java\\abc.txt\\student1.txt"));
        Object o = ois.readObject();
//        ArrayList o1 = (ArrayList) o;
        ArrayList<Student> o1 = (ArrayList<Student>) o;
        for (Object o2 : o1) {
            System.out.println(o2);
        }
        ois.close();
        oos.close();

    }
}


posted @ 2021-05-07 18:57  牛牛ō^ō  阅读(29)  评论(0编辑  收藏  举报