前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >序列化的一些注意事项及建议

序列化的一些注意事项及建议

作者头像
石臻臻的杂货铺[同名公众号]
发布2021-07-14 09:53:59
3170
发布2021-07-14 09:53:59
举报
文章被收录于专栏:kafka专栏

本文来自《改善java的151个建议》

建议11:养成良好习惯,显示声明UID

我们先写一个序列化与反序列化的工具类SerilizationUtils

代码语言:javascript
复制
public class SerializationUtils {

	private static String FILE_NAME="E:/serializable.txt";
	
	public static void writeObject(Serializable s){
		try{
			
			
			ObjectOutputStream oob = new ObjectOutputStream(new FileOutputStream(FILE_NAME));
			oob.writeObject(s);
			oob.close();
		}catch(Exception e){};
	}
	
	public static Object readObject(){
		Object obj=null;
		try{
			
			ObjectInputStream oob = new ObjectInputStream(new FileInputStream(FILE_NAME));
			obj = oob.readObject();
			
			oob.close();
		}catch(Exception e){};
		
		return obj;
	}
}

Person类

代码语言:javascript
复制
public class Person implements Serializable  {

	/**
	 * 这里先不显示的声明UID
	 */
	//private static final long serialVersionUID = 1L;

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	//
	/*private String sex;

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}*/
	
}

首先定义一个消息的产生者Produce

代码语言:javascript
复制
public class Produce {

	public static void main(String[] args){
		
		Person person = new Person();
		person.setName("****");
		
		//增加sex后
		//person.setSex("男");
		//序列化 保存到磁盘上

		SerializationUtils.writeObject(person);
		System.out.println(person);
	}
}

这里执行了之后  person就被序列化到了E:/serializable.txt

然后定义一个消费者

代码语言:javascript
复制
public class Consumer {
	
	public static void main(String[] args) throws Exception{
		
		//反序列化
		Person p = (Person)SerializationUtils.readObject();
		System.out.println("反序列化得到的值"+p.getName());
		//System.out.println("反序列化得到的值"+p.getSex());
	}

}

好 运行到这里是没有什么问题的;但是如果我们序列化与反序列化的时候参照的不是一个Person  会出现什么情况  ;

比如我们在序列化之前person还是只有一个属性name   执行produce (序列化)之后;给person增加一个sex属性(注意不要再运行produce (序列化)了);

增加了属性之后   我们运行consumer(反序列化);会出现一个错误

书上说的是InvalidClassException错误;但是我亲自执行报的是上面的错误;

为什么会这样呢?

原因是序列化与反序列化对应的类(person)版本不一致;JVM不能把数据流转换为实例对象;

那JVM是怎么判断一个类的对应版本呢?

是通过SerivalVersionUID ,也就流标识符,即类的版本定义

代码语言:javascript
复制
private static final long serialVersionUID = 1L;

UID可以隐式声明和显示声明;隐式声明是编译器自动生成  基本上市唯一的;如果改变了类 ; 它是UID也会改变

在反序列化的时候 jvm会比较数据流中的UID与当前类(person)是否一致;如果一致说明类没有改动;不一致说明是改动了,这是一个很好的效验机制;

但是;有特殊情况;例如:我的类改变不大,我希望在反序列化的时候也能把它序列化出来。那怎么办呢?

既然是判断UID是否一致,那我们让他们的UID是一致的就可以了,显示声明UID 可以很好的解决这一问题;

建议12:避免用序列化类在构造函数中未不变量final赋值

代码语言:javascript
复制
private static final long serialVersionUID = 1L;
	
	//final 常量是一个直接量   在反序列化的时候就会重新计算  保持final对象的新旧统一  有利于代码业务逻辑统一
	
	public final String testFinal="序列化之前";
//	public final String testFinal="序列化之后";

序列化的时候给testFinal赋值是   序列化之前           

序列化完成之后   将testFinal改成    序列化之后   

然后执行反序列化

代码语言:javascript
复制
	//反序列化
		Person p = (Person)SerializationUtils.readObject();
		
		System.out.println("反序列化得到的值:"+p.testFinal);

输出来的值是   序列化之前还是之后呢? 

输出结果是:反序列化得到的值:序列化之后

为什么呢?我们在序列化的时候 将testFinal序列化成了数据流存在了磁盘中  按理说反序列化的时候  得到的也是  序列化之前的值啊    为什么变成了序列化之后?

这是因为序列化的基本规则之一:保持final新旧对象的相同。有利于代码业务逻辑的统一;也就是说,如果final是一个直接量  则反序列化时候final就会被重新计算;

final变量的另外一种赋值:构造函数赋值

代码语言:javascript
复制
public final String testFinal;

	public Person() {
		// TODO Auto-generated constructor stub
		testFinal="构造函数赋值  之前";
	}

序列化之后修改

代码语言:javascript
复制
testFinal="构造函数赋值  之后";

然后进行反序列化;猜想:这里输出应该会是   构造函数赋值  之后   吧?  因为规则一也是这样的啊!

那到底输出什么呢?

代码语言:javascript
复制
反序列化得到的值:构造函数赋值  之前

为什么还是之前  而不是改变之后的呢?  原因是另一个规则

反序列化时构造函数不被执行!

建议13:避免为final变量复杂赋值

总结:反序列化在以下情况不能够被重新赋值

1、通过构造函数为final变量赋值

2、通过方法未final变量赋值

3、final修饰的对象不是基本对象

建议14:使用序列化类的私有方法巧妙解决  部分属性  持久化问题

......

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014/12/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档