序列化与反序列化
- 序列化:把对象按照流一样的方式存到文本文件或者数据库或者网络中传输等等。
对象 -- 流数据:ObjectOutputStream
- 反序列化:把文本文件中的对象或者网络中的流数据给还原成一个对象的过程。
流数据 -- 对象:ObjectInputStream
未序列化异常
- NotSerializableException: com.shujia.wyh.day25.Person
只有支持java.io.Serializable接口的对象才能写入流中。
类的序列化由实现java.io.Serializable接口的类启用。
不实现此接口的类将不会使任何状态序列化或反序列化。
可序列化类的所有子类型都是可序列化的。
观察API
- 通过观察API发现,Serializable接口中没有任何抽象方法和常量,说明它是一个标记接口。
(回想一下,我们之前说过的Object类中的克隆)
当写入对象数据后,在读取数据之前,将对象属性发生改变,或者其他改变操作会发生异常
- java.io.InvalidClassException: com.shujia.wyh.day25.Person;
local class incompatible:
stream classdesc serialVersionUID = 8333181233940260538,
local class serialVersionUID = -2276749375407741261
即改变前后的 serialVersionUID 值发生改变,
形象理解
在没有进行修改类之前:
- Person.class -- id=100
写数据的适合:object -- id=100
读数据的时候:object -- id=100
- 在进行修改后(删除了一个private)
Person.class -- id=200
之前写的时候:object -- id=100
读数据的时候:object -- id=100
解决办法:
- 在实际开发中,因为业务的问题,不允许重复地往文件中或者数据库中重复写入,那怎么解决呢?
- 这个问题本质上是由于id值地不匹配导致地,如果说有一个办法,无论我怎么修改class类,这个id值都不会变化就好了。
Java在序列化中提供了一个ID值,可以让我们去设定。
我们不需要手动去设定,自动生成即可。
设置:
- idea - 设置 - inspecttions - 在搜索栏中搜索 serializable 修改两个属性就好使用办法:光标放在 类名上,按下Alt+ enter.
类中属性并不想被序列化,解决办法
- java提供了一个关键字给我们使用,可以让我们在序列化的时候选择哪些成员变量不被序列化
transient
代码
自定义类代码
public class Person implements Serializable {
private static final long serialVersionUID = -2276749375407741261L;
private String name;
// private int age;
transient int age;
public Person() {
}
public Person(String name, int age) {
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 +
'}';
}
}
main方法代码
public class ObjectOutputStreamDemo1 {
public static void main(String[] args) {
//写数据,序列化,将一个对象存到一个文件中,这个过程叫做序列持久化。
// write();
read();
}
public static void read(){
//创建对象输入流
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("src\\com\\shujia\\wyh\\day25\\obj.txt"));
//调用方法读取数据
Object o = ois.readObject();
// System.out.println(o);
//要想使用读取到的对象类型中的方法,就得向下转型
Person p = (Person) o;
System.out.println(p);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(ois!=null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void write(){
ObjectOutputStream oos = null;
//创建一个对象输出流
try {
oos = new ObjectOutputStream(new FileOutputStream("src\\com\\shujia\\wyh\\day25\\obj.txt"));
//创建一个对象
Person p = new Person("李毅", 18);
//调用方法,将对象写入到文件中进行存储
oos.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(oos!=null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}