序列化流
1.简介
将短期存储的数据实现长期存储,这个过程对应的流就是序列化流
数据的存储分成两类
- 短期存储:存放在内存中,随着程序的关闭而释放。如:对象、集合、变量、数组等
- 长期存储:存储在磁盘中,即使程序关闭了,数据依然存在。如:文件
序列化:将数据从内存放入磁盘中,可以实现数据的长久保存。
反序列化:将数据从磁盘放入内存中。
2.注意事项
ObjectInputStream、ObjectOutputStream,主要是用来做对象的序列化和反序列化的。
序列化、反序列化,是对象的持久化存储的一种常用手段。
所有的序列化到本地的类的对象,类必须实现java.io.Serilizable接口。
实现Serilizable接口的类可以达到的目的:
- 可以进行序列化
- 进行序列化的类的元素必须都支持序列化
- 可序列化类的所有子类型本身都是可序列化的
- 接口本身没有方法或字段,只是用来表示可序列化的语义
如果需要序列化多个文件到本地,尽量不要序列化到一个文件中。如果需要序列化多个文件到本地,通常采用的方法是存集合。将多个对象存入一个集合中,然后将这个集合序列化到本地中。
3.常见问题
- ClassNotFoundException:当前的类没有找到
原因:反序列化在执行的时候依赖字节码文件,当类没有类,字节码文件无法创建,反序列化失败 - java.io.InvalidClassException:无效的类
原因:没有声明自己的serialVersionUID,而使用的系统的,在进行反序列化的时候类被改动了,系统认为现在的类已经不是原来的类了,认为此类无效 - 使用系统的serialVersionUID和自定义UID的区别?
使用系统的的UID的时候:id不能手动设置,使用的是编译器默认生成的。一旦类发生了改动,id会重新赋值;
使用自定义的UID的时候:序列化和反序列化的时候,id不会发生变化。所以当反序列的时候,即使对类进行了一些改动,也能继续反序列化。
示例代码
package com.cq.test;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author: Mercury
* Date: 2022/4/6
* Time: 9:02
* Description:序列化流
* Version:1.0
*/
public class SerializableTest {
public static void main(String[] args) {
test1();
test2();
}
//序列化
public static void test1(){
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:\\bigDataWorkSpace\\part01\\day21_0406\\person.txt"));){
//对对象进行序列化
List<Person> list = new ArrayList<>();
list.add(new Person("张三",20,177));
list.add(new Person("wangwu",21,177));
//可序列化类的所有子类本身都是可序列化的
list.add(new Child("lisi",20,155,100));
//将多个对象序列化的时候,需要先放入一个集合中,然后再序列化
objectOutputStream.writeObject(list);
} catch (IOException e) {
e.printStackTrace();
}
}
//逆序列化
public static void test2(){
try(ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("F:\\bigDataWorkSpace\\part01\\day21_0406\\person.txt"));) {
//反序列化
//反序列多个对象的时候,同样需要一个集合来保存反序列化的多个对象
List list = (ArrayList)objectInputStream.readObject();//需要强制转换ArrayList
System.out.println(list);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//Person类的对象可以实现序列化,必须让其实现Serializable接口
class Person implements Serializable{
// UID由用户进行指定,默认值为1L
public static final long serialVersionUID = -24323423423423221L;
private String name;
private int age;
private double height;
public void show(){
System.out.println("show--Person");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
public Person() {
}
public Person(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
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;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
}
//可序列化类的所有子类本身都是可序列化
class Child extends Person{
private double weight;
public Child() {
}
public Child(double weight) {
this.weight = weight;
}
public Child(String name, int age, double height, double weight) {
super(name, age, height);
this.weight = weight;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Child{" +
"weight=" + weight +
'}';
}
}
注意:
- 要想对象可以实现序列化,那么必须让该类实现Serializable接口
- 未实现Serializable接口的类无法使其任何状态序列化或反序列化
- 不仅要求当前类可序列化,而且要求当前类的所有元素本身都是可序列化的
- 将多个对象序列化的时候,需要将其先放入一个集合中,然后再进行序列化;反序列化的时候同样,但需要类型强制转换
总结
- 合理使用序列化流和反序列化流,要与输入流和输出流配合使用
- 进行序列化的类一定要实现Serializable接口,只要实现了接口就可以序列化,包括集合、包装类等
- 进行序列化的类要保证当前类与内部的类都要实现Serializable接口
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/116589.html