java序列化之serialversionuid
今天讲一讲java对象中的serialversionuid,先从序列化讲起。
什么是序列化
序列化,简单的说,就是将一个对象转化(编码)成可以传输的输出流(字节流)。而反序列化就是序列化的逆过程,将输入流转化(构建)成一个对象。
为什么要序列化
字节流可以用于网络传输和存储在磁盘,而对象需要转化成字节流才能在网络中传输和在磁盘上存储。
网络传输就好比打电话,声音是无法直接从电话的一端传到另一端,因此需要将声音转成电信号进行传播。
另一方面,java对象是保存在jvm的堆内存中的,也就是说,如果jvm堆不存在了,那么对象也就跟着消失了,而序列化提供了可以把对象保存下来的方案。
serialversionuid是个啥
说到序列化,serialversionuid是个不得不谈的话题。
serialversionuid 是 java 为每个序列化类(实现java.io.serializable接口的类)产生的版本标识, 可用来保证在反序列时,发送方发送的和接受方接收的是可兼容的对象。
如果接收方接收的类的 serialversionuid 与发送方发送的 serialversionuid 不一致,进行反序列时会抛出 invalidclassexception。
怎么生成serialversionuid
下载generateserialversionuid插件,就可以自动生产这个序列类的serialversionuid了。

serialversionuid是一成不变的吗
达咩!
serialversionuid 是 java 为每个序列化类产生的版本标识!!
java序列化机制会根据编译的class自动生成一个serialversionuid作序列化版本比较用。
如果class文件的类名、方法名称发生改变,serialversionuid就会改变。
如果class文件没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialversionuid也不会变化的。
import java.io.serializable;
public class person implements serializable {
// 原本的serialversionuid
private static final long serialversionuid = 904xxxxxxxxxx662l;
private int age;
private string name;
private string address;
public person(int age, string name, string address) {
this.age = age;
this.name = name;
this.address = address;
}
public int getage() {
return age;
}
public void setage(int age) {
this.age = age;
}
public string getname() {
return name;
}
public void setname(string name) {
this.name = name;
}
public string getaddress() {
return address;
}
public void setaddress(string address) {
this.address = address;
}
}
import java.io.serializable;
public class person implements serializable {
// 加上tosting函数的serialversionuid
private static final long serialversionuid = 841xxxxxxxxxxxxx884l;
private int age;
private string name;
private string address;
public person(int age, string name, string address) {
this.age = age;
this.name = name;
this.address = address;
}
public int getage() {
return age;
}
public void setage(int age) {
this.age = age;
}
public string getname() {
return name;
}
public void setname(string name) {
this.name = name;
}
public string getaddress() {
return address;
}
public void setaddress(string address) {
this.address = address;
}
@override
public string tostring() {
return "person{" +
"age=" + age +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
如果我手动改了serialversionuid=11111111l会怎样?如果接收方接收的类的 serialversionuid 与发送方发送的 serialversionuid 不一致,进行反序列时会抛出 invalidclassexception。
exception in thread "main" java.io.invalidclassexception: serializablestudy.person; local class incompatible: stream classdesc serialversionuid = 841xxxxxxxxxxxxx884, local class serialversionuid = 11111111
序列化和反序列化
序列化要把对象写入输出流中,反序列化就是将输出流重新构建对象,二者为逆过程。当serialversionuid改变时,一定要重新序列化,再进行反序列化。
话不多说,放代码。
以下是基于上面序列化类person,做序列化和反序列化的演示:
public class serialtest {
public static void main(string[] args) throws ioexception {
// 序列化
person p = new person(0,"aaa","bbbbb");
// 指定文件生成输出流
fileoutputstream fos = new fileoutputstream("person.txt");
// 将对象写出到指定的输出流
objectoutputstream oos = new objectoutputstream(fos);
// 将指定的对象写入objectoutputstream。
oos.writeobject(p);
// 刷新流
oos.flush();
oos.close();
}
}
public class deserialtest {
public static void main(string[] args) throws ioexception, classnotfoundexception {
// 反序列化
// 根据指定文件生产输入流
fileinputstream fis = new fileinputstream("person.txt");
// 从指定的输入流中读回对象消息
objectinputstream ois = new objectinputstream(fis);
// 从objectinputstream读取一个对象
person p = (person) ois.readobject();
ois.close();
system.out.println(p.tostring());
}
}
输出的结果为:

注意:
将指定对象写入objectoutputstream时,存储针对对象本身而不是针对类,没有实现序列化的类不会参与序列化和反序列化!!
举个例子,如果person中设置一个没有实现序列化的父类home:
public class home {
private string home;
public string gethome() {
return home;
}
public void sethome(string home) {
this.home = home;
}
}
public class person extends home implements serializable {
......
}
在序列化和反序列化的过程中,即使定义了person对象的home属性,由于home中没有实现序列类,因此对象的home属性不会进行序列化处理。

总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论