java序列化之serialVersionUID

上次去面试的时候被问到一个关于序列化的问题:序列化怎么解决版本问题,即在我序列化之后,如果我又改了被序列化的那个类,我怎么反序列化它。当时被问懵了,回来也忘了查。今天在做一个java web项目时,在servlet中没有定义serialVersionUID而被eclipse标记为黄色提示,一直不懂这个serialVersionUID是干啥子用的,于是趁有空就搜了一下,发现它就是解决序列化版本问题的关键。

还是用例子来说明吧,首先建一个普通类:

import java.io.*;
public class Person implements Serializable{
	private String name;
	public Person(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String toString() {
		return "name=" + name;
	}
}
然后序列化这个类:

import java.io.*;
public class WhySerialversionUID_Write {
	public static void main(String[] args) throws Exception{
		Person p = new Person("zhengjunyan");
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
		oos.writeObject(p);	
		oos.close();
	}
}
再反序列化它:

import java.io.*;
public class WhySerialversionUID_Read{
<span style="white-space:pre">	</span>public static void main(String[] args)  throws Exception{
<span style="white-space:pre">		</span>ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
<span style="white-space:pre">		</span>Person p = (Person)ois.readObject();
<span style="white-space:pre">		</span>System.out.println(p);
<span style="white-space:pre">	</span>}
}
此时一切正常:


然后再修改Person类,如添加一个字段:

import java.io.*;
public class Person implements Serializable{
	private String name;
	private int age;//添加了这个字段
	public Person(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String toString() {
		return "name=" + name;
	}
}
再次反序列化,将会报如下错误:


它说字节流中的serialVersionUID跟我们本地这个Person类的serialVersionUID不匹配。原来,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本的一致性的,在进行反序列化时,jvm会把传来的字节流中的serialVersionUID跟本地相应的类的serialVersionUID作比较,如果不相同则不会进行反序列化。

那如果我们在序列化后想对类增加字段或方法等怎么办呢?我们可以给类定义一个serialVersionUID字段并赋值,因为java在序列化某个类时,如果我们给类的serialVersionUID赋了值,他就会用我们给定的这个serialVersionUID来标示版本,如果我们没有给,他就会自动给这个class执行某个算法,得到一个serialVersionUID,这样的话只有类保存不变,它的serialVersionUID才会相同。

所以如果要保证修改后的版本能被正常的反序列化,可以给类添加一个字段serialVersionUID,例如:

import java.io.*;
public class Person implements Serializable{
	private static final long serialVersionUID = 1L;
	private String name;
	//private int age;
	public Person(String name){
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String toString() {
		return "name=" + name;
	}
}
跟上面同样的做法,先序列化再反序列化,正常;再去掉Person类的注释,即添加一个字段age,再反序列化,仍然正常。

这也解释了eclipse为什么要我们为servlet添加字段serialVersionUID的原因了,因为java的HttpServlet(当然还有其父类等)实现了serializable接口,而根据上面所述,若实现了序列化接口,为了版本的维护需要,最好是给定一个serialVersionUID字段。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值