序列化和反序列化的概念
- 序列化:把对象转换为字节序列的过程
对象序列化过程可以分为两步:
第一: 将对象转换为字节数组
第二: 将字节数组存储到磁盘 - 反序列化:把字节序列恢复为对象的过程
反序列化的作用
- 内存中的对象状态保存到一个文件中或者数据库中
- 用套接字在网络上传送对象
- 通过RMI传输对象
如何实现反序列化
实现Serializable接口,具体看代码
package xfgg;
import java.io.Serializable;
public class FlyPig implements Serializable{
private static String AGE = "269";
private String name;
private String color;
transient private String car;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getColor(){
return color;
}
public void setColor(String color){
this.color = color;
}
public String getCar(){
return car;
}
public void setCar(String car){
this.car = car;
}
@Override
public String toString(){
return "FlyPig{"+
"name='"+name+'\''+
", color='"+ color +'\''+
", car='"+ car +'\''+
", AGE='"+ AGE +'\''+
'}';
}
}
//main 方法
package xfgg1;
import xfgg.FlyPig;
import java.io.*;
public class SerializableTest {
public static void main(String[] args) throws Exception {
serializeFlyPig();
FlyPig flyPig = deserializeFlyPig();
System.out.println(flyPig.toString());
}
/**
* 序列化
*/
private static void serializeFlyPig() throws IOException {
FlyPig flyPig = new FlyPig();
flyPig.setColor("black");
flyPig.setName("naruto");
flyPig.setCar("0000");
// ObjectOutputStream 对象输出流,将 flyPig 对象存储到E盘的 flyPig.txt 文件中,完成对 flyPig 对象的序列化操作
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/flyPig.txt")));
oos.writeObject(flyPig);
System.out.println("FlyPig 对象序列化成功!");
oos.close();
}
/**
* 反序列化
*/
private static FlyPig deserializeFlyPig() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/flyPig.txt")));
FlyPig person = (FlyPig) ois.readObject();
System.out.println("FlyPig 对象反序列化成功!");
return person;
}
}
ObjectOutputStream代表对象输出流:
它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
ObjectInputStream代表对象输入流:
它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
序列化运行结果
会在d盘生成flypig.txt文件
transient修饰的属性,是不会被反序列化的
静态static属性不序列化
serialVersionUID的作用和用法
package xfgg;
import java.io.Serializable;
public class FlyPig implements Serializable {
private static final long serialVersionUID = 1L;
private static String AGE = "269";
private String name;
private String color;
transient private String car;
private String addTip;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
public String getAddTip() {
return addTip;
}
public void setAddTip(String addTip) {
this.addTip = addTip;
}
@Override
public String toString() {
return "FlyPig{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", car='" + car + '\'' +
", AGE='" + AGE + '\'' +
", addTip='" + addTip + '\'' +
'}';
}
}
就是在实现这个Serializable 接口的时候,一定要给这个 serialVersionUID 赋值
可以简单的赋值个 1L,这就可以啦。。这样可以确保代码一致时反序列化成功。
不同的serialVersionUID的值,会影响到反序列化,也就是数据的读取,你写1L,注意L大些。计算机是不区分大小写的,但是,作为观众的我们,是要区分1和L的l,所以说,这个值,闲的没事不要乱动,不然一个版本升级,旧数据就不兼容了,你还不知道问题在哪
jdk api中关于serialVersionUID的描述
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 “serialVersionUID” 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java™ 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 – serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。