序列化 & 反序列化
序列化应用场景:
比如你用电脑在淘宝上购物,当你准备付款时电脑断电了,此时在服务器端已经创建对象。
服务器端会这个保留对象一段时间,如果这是用户还未进行相关处理,服务器为了减少资源
消耗,就会将这个对象写入硬盘中。将内存中对象写入硬盘中的过程叫做 序列化。
序列化ObjectOutputStream
package com.company01.IO;
/*
java.io.ObjectOutputStream; 序列化JAVA对象到硬盘。(Serial)
java.io.ObjectInputStream; 将硬盘中的数据“反序列化”到内存。(DeSerial)
Compile 编译(java --> Class文件)
DeCompile 反编译(Class --> java文件)
*/
import java.io.*;
import java.io.Serializable; // 该接口是一个"可序列化"的
// 该接口没有任何方法,是一个标识接口
// 像这样的接口还有:java.lang.Cloneable; 可克隆的
public class ObjectOutputStreamTest01 {
public static void main(String[] args) throws Exception{
// 1.创建java对象
User u1 = new User("刘德华");
// 2.创建输出流(序列化流)(JVM中的java对象状态保存到硬盘中)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test04"));
// 3.写
oos.writeObject(u1);
// 刷新
oos.flush();
// 关闭
oos.close();
}
}
/*
标识接口的作用:起到标识的作用。
JVM如果看到该对象实现了某个标识接口,会对它特殊待遇。
疑问:User实现Serializable接口,JVM对它的特殊待遇是什么?
*/
class User implements Serializable{
String name;
User(String name){
this.name = name;
}
public String toString(){
return "User[name:" + name + "]";
}
}
反序列化ObjectInputStream
package com.company01.IO;
/*
反序列化
*/
import java.io.*;
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws Exception{
// 1,创建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test04"));
// 2.反序列化
Object o = ois.readObject();
System.out.println(o); // 默认调用o.toString()
// 关闭
ois.close();
}
}
序列化版本号
package com.company01.serialVersionUID;
import java.io.Serializable;
/*
因为User实现了Serializable接口,JVM会特殊待遇:
会给该类添加一个属性,static final long serialVersionUID = xxx...;
当类发生改变后,该属性值会发生改变。
可以不让系统自动生成,自己直接写一个序列化版本号
*/
public class User implements Serializable{
// 可以不让系统自动生成,自己直接写一个序列化版本号
static final long serialVersionUID = -294795583033464129L;
String name;
// 如果不想让该属性参加序列化,需要使用trainsient关键字修饰
// 被trainsient关键字修饰的属性,在反序列化的时候,所有对象中该属性值都默认为 该属性类型类型的默认初始化值(int:0;String:null;...)。
transient int age;
User(String name, int age){
this.age = age;
this.name = name;
}
public String toString(){
return "User[name:" + name + ",age:" + age + "]";
}
}
package com.company01.serialVersionUID;
import java.io.*;
// 序列化
public class Test01 {
public static void main(String[] args) throws Exception{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.DBF")); // DBF数据库文件
User u = new User("zhangsan", 23);
oos.writeObject(u);
oos.flush();
oos.close();
}
}
package com.company01.serialVersionUID;
/*
当User.java改变后编译,生成的User.Class文件发生改变
在没有重新进行序列化的倩况下,执行先前的反序列化,会报错
Exception in thread "main" java.io.InvalidClassException: com.company01.serialVersionUID.User;
local class incompatible:
stream classdesc serialVersionUID = -294795583033464129, 流里面的class描述用的序列化版本号
local class serialVersionUID = -1356840406334401512 本地的class文件中序列化版本号
当两个版本号不一致时,JVM认为是不兼容的两个类。
因为User实现了Serializable接口,JVM会特殊待遇:
会给该类添加一个属性,static final long serialVersionUID = xxx...;
当类发生改变后,该属性值会发生改变。
*/
import java.io.*;
// 反序列化
public class Test02 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.DBF"));
System.out.println(ois.readObject());
ois.close();
}
}