Java学习-IO流-序列化流
字节流
↙ ↘
InputStream OutputStream
↓ ↓
反序列化流 序列化流
ObjectInputStream ObjectOutputStream
序列化流
序列化流/对象操作输出流:把java中的对象写到本地文件中
public ObjectOutputStream(OutputStream out):把基本流包装成高级流
public final void writeObject(Object obj):把对象序列化(写)到文件中
public class Student {
private String name;
private int age;
}
Student stu = new Student("zhangsan",23);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\xx.txt"));
oos.writeObject(stu);
oos.close();
//报错:NotSerializableException
解决方案:让Javabean类实现Serializable接口,没有抽象方法,标记型接口,一旦实现了这个接口,就表示当前的类可以被序列化
public class Student implements Serializable{
private String name;
private int age;
}
Student stu = new Student("zhangsan",23);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\xx.txt"));
oos.writeObject(stu);
oos.close();
反序列化流
反序列化流/对象操作输入流:把序列化到本地文件的对象数据读取到程序中
public ObjectInputStream(InputStream in):把基本流包装成高级流
public Object readObject():把序列化到本地文件中的对象读取到程序中
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\xx.txt"));
Object o = ois.readObject();
sout(o);
ois.close();
序列化流和反序列化流使用细节
版本号
将 Student 类对象 stu 序列化到本地文件后,在 Student 类中新增属性 address
public class Student implements Serializable{
private String name;
private int age;
private String address;
}
再将 stu 反序列化到程序中时会报错
分析原因:
在类实现 Serializable 接口时,java 会根据类的属性、方法等信息计算一个 long 类型序列号,在类实例化时,对象会包含这个序列号,在对象序列化时,序列号也一起被写到本地文件中;在类新增属性后,会重新计算版本号,导致反序列化时两个版本号不一致,因此会报错
解决方案:
固定版本号
法1:
public class Student implements Serializable{
private static final long serialVersionUID=1L;
private String name;
private int age;
}
法2:
File → Settings → 搜索 Serializable → 选中Serializable class without ‘serialVersionUID’ → 选中Transient field is not initialized deserialization → OK
未定义序列号的类会被标记,鼠标悬停时会提示:does not define a ‘serialVersionUID’ field,选中类,Alt + 回车 → Add ‘serialVersionUID’ field,自动计算版本号
@Serial
private static final long serialVersionUID = -123456789L;
验证效果
定义类
public class Student implements Serializable{
private static final long serialVersionUID = -123456789L;
private String name;
private int age;
}
序列化对象
Student stu = new Student("zhangsan",23);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\xx.txt"));
oos.writeObject(stu);
oos.close();
修改类属性
public class Student implements Serializable{
private static final long serialVersionUID = -123456789L;
private String name;
private int age;
private String address;
}
反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\xx.txt"));
Object o = ois.readObject();
sout(o);
ois.close();
输出:Student{name=‘zhangsan’,age=23,address=‘null’}
限制某些属性不被序列化到本地文件
transient:瞬态关键字,不会把它修饰的属性序列化到本地文件
public class Student implements Serializable{
private static final long serialVersionUID = -123456789L;
private String name;
private int age;
private transient String address;
}
序列化对象
Student stu = new Student("zhangsan",23,"天津");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\xx.txt"));
oos.writeObject(stu);
oos.close();
反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\xx.txt"));
Object o = ois.readObject();
sout(o);
ois.close();
输出:Student{name=‘zhangsan’,age=23,address=‘null’}
小结
1.类应实现 Serializable 接口,否则报错 NotSerializableException
2.序列化到本地文件中的数据是不能被修改的,一旦修改无法读取
3.序列化后,修改了类,再反序列化,会报错:InvalidClassException,解决方案:SerialVersionUID
4.transient:限制某个属性不参与实例化过程