【JAVA入门】Day43 - 序列化流和反序列化流
文章目录
序列化流和反序列化流是字节流下的高级流类。
序列化流的作用是:把 Java 中的对象写到本地文件中。
反序列化流的作用是:把本地文件中的 Java 对象读入。
一、序列化流(对象操作输出流)
把 Java 中的对象写到本地文件中。其中包含的方法如下:
利用这两个方法,我们可以把 Java 中的一个对象写入本地文件。但要注意,直接将对象输出会出现 NotSerializableException 异常,这是因为 Javabean 类本身是不允许被序列化的,我们要先让 Javabean 类实现一个 Serializable 接口。这个接口是一个标记型接口,一旦实现了这个接口,就表明当前这个 Javabean 类可以被序列化。
package ObjectStream;
import java.io.Serializable;
import java.util.Objects;
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package ObjectStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
利用序列化流把一个对象写到本地中
*/
//1.创建对象
Student student = new Student("zhangsan",23);
//2.创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\IdeaProjects\\HelloWord\\src\\ObjectStream\\student.txt"));
//3.把对象输出到文件
oos.writeObject(student);
//4.释放资源
oos.close();
}
}
二、反序列化流(对象操作输入流)
反序列化流可以把序列化到本地文件中的对象,读取到程序中来。
反序列化流读入的对象类型是 Object 类,我们还要进行一次强制转换,把它转成本来的类型。
package ObjectStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectStreamDemo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
/*
利用反序列化流把本地文件中的对象读取到程序中来
*/
//1.创建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\IdeaProjects\\HelloWord\\src\\ObjectStream\\student.txt"));
//2.读入数据
//Object obj = ois.readObject();
Student student = (Student) ois.readObject();
//3.打印对象
//System.out.println(obj);
System.out.println(student);
//4.释放资源
ois.close();
}
}
三、序列化流和反序列化流的使用细节
3.1 序列号
如果一个类实现了 Serializable 接口,就代表这个类是一个可序列化的,然后 Java 会根据这个类的构造方法、静态变量、静态方法、成员变量、成员方法等内容进行计算,生成一个 long 类型的序列号。此时如果把这个对象写入本地文件当中,这个序列号也是会被写入的。
一旦我们又修改了这个类的内容(比如新增了属性),Java 又会重新计算一个序列号。此时,用反序列化流把本地文件读取进来的时候,就会报错。报错原因很简单:文件中的版本号,跟 Javabean 的版本号不匹配。
因此如果我们想要反复修改一个类,然后对它反复使用序列化流和反序列化流,就需要在 Javabean 类中提前设定好它的版本号,这样每次修改时,其序列号就不会改变了,也就可以反复序列化和反序列化了。
序列号的格式如下:
private static final long serialVersionUID = 1L;
注意它是一个私有静态常量,不可被方法修改,且名字必须叫“serialVersionUID”。
package ObjectStream;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.2 不想序列化到本地的成员变量
如果 Javabean 里的某些属性,你不想序列化到本地(保护隐私),那么你可以在变量前加一个关键字 transient 。
private transient String address;
package ObjectStream;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private transient String address;
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
四、读写多个对象
如果有多个对象想要同时读写,应该如何操作呢?
我们可以把多个对象放入一个ArrayList,序列化这个 list 对象。
package ObjectStream;
import java.io.*;
import java.util.ArrayList;
public class ObjectStreamDemo3 {
public static void main(String[] args) throws IOException {
/*
序列化读写多个对象
*/
//1.序列化多个对象
Student s1= new Student("zhangsan", 23, "南京");
Student s2= new Student("lisi",24,"北京");
Student s3= new Student("wangwu",25,"上海");
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
//直接序列化list对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\IdeaProjects\\HelloWord\\src\\ObjectStream\\student.txt"));
oos.writeObject(list);
oos.close();
}
}
再反序列化这个 list 对象即可。
package ObjectStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
public class ObjectStreamDemo4 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
/*
反序列化多个对象
*/
//1.创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\IdeaProjects\\HelloWord\\src\\ObjectStream\\student.txt"));
//2.读取list对象
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
//3.打印
for (Student student : list) {
System.out.println(student);
}
}
}