Java保存对象

这篇博客详细介绍了Java对象的序列化和反序列化过程,包括如何将序列化对象写入文件,如何通过序列化还原对象。文章强调了可序列化接口Serializable的作用,以及transient关键字在序列化中的意义。此外,还讨论了版本控制问题,特别是当类被修改后如何处理序列化ID以避免解序列化错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 将序列化对象写入文件

一般流程:

//可能会产生异常
try {
			//打开文件
			FileOutputStream fileStream=new FileOutputStream("MyGame.ser");
			//创建对象输出流
			ObjectOutputStream oStream=new ObjectOutputStream(fileStream);
			//写入对象
			oStream.writeObject(new Integer(1));
			//关闭对象输出流
			oStream.close();
			//关闭文件流
			fileStream.close();
}catch (Exception e) {
			e.printStackTrace();// : handle exception
}

  1. 对象存储了什么?

在存储对象时,我们想的是恢复对象后能和存储时有一样的状态。但是如果在对象中有其它对象成员呢,我们知道在对象中保存的实际是其它对象的引用,真正的对象在堆上其它地方。如果只保存此对象的引用,显然在恢复时会出错误。

序列化程序会将对象版图上的所有东西存储起来。被对象的实例变量所引用的所有对象都会被序列化。
例如:zoo对象中有Lion[] lionArray对象,lionArray对象中又有多个lion,那么在存储zoo时,lionArray和其中的lion都会被序列化存储。

  1. 可序列化接口Serializable与不可序列化关键词transient

如果要让自己设计的类可以被序列化存储,就实现Serializable接口,不需要实现任何方法。实现了此接口的类,其子类也可以序列化。

如果要让一个类可序列化,那么此类中的所有成员都应该是可序列化的,即整个对象版图都必须正确地序列化,不然就全部失败。

如果某实例变量不能不应该被序列化,就把它标记为transient(瞬时)的。

某类可序列化但其父类不可序列化的情况:
当对象被还原且它的父类不可序列化时,父类的构造函数会跟创建新的对象一样执行。

有多个引用指向同一个对象的情况:
只有一个对象会被存储,恢复后原引用仍指向同一对象。

如果某个实例被标记为transient的:
那么在恢复时会默认设为null,如果该值很重要,可通过其它方法保存其值,待恢复后再将值赋给它。

2 解序列化:还原对象

一般流程:

try {
			//打开文件
			FileInputStream fileStream=new FileInputStream("MyGame.ser");
			//创建对象输入流
			ObjectInputStream iStream=new ObjectInputStream(fileStream);
			//读取对象
			Object oneObject=iStream.readObject();
			//转换对象
			Integer aInteger=(Integer)oneObject;
			//关闭对象输入流
			iStream.close();
			//关闭文件输入流
			fileStream.close();
		} catch (Exception e) {
			e.printStackTrace();// TODO: handle exception
	}
  1. 对象恢复时发生了什么

在恢复对象时,java虚拟机首先通过存储信息判断对象的class类型,如果无法加载该类型则抛出异常。

新的对象被配置在堆上,但其构造函数不会执行,如果其某个父类是不可序列化的,则该父类及其之上的父类的构造函数会执行。

未被标记为transient的变量会恢复成存储时的内容,被标记为transient的变量会被设置为0、false或null。

静态变量不会被序列化。

3 版本控制

如果对象被保存后,它原来的类被修改了,这样在读取对象时就有可能会出错。例如原来类中的某个变量被删除了,或者类型被修改等等。有些修改会损害解序列化,有些不会。

会损害解序列化的修改通常不会有事的修改
删除实例变量加入新的实例变量(会使用默认值)
改变实例变量的类型在继承层次中加入新的类
将非瞬时的实例变量改为瞬时的从继承层次中删除类
改变类的继承层次不会影响解序列化程序设定变量值的存取层次修改
将类从可序列化改成不可序列化的将实例变量从瞬时改成非瞬时(会使用默认值)
将实例变量改成静态的

每当对象被序列化的同时,该对象都会被加上一个类的版本识别ID,被称为serialVersionUID,在还原对象时,会对比对象与java虚拟机上类的serialVersionUID,只有相同才会判定为相同的类。

在修改了类之后通常修改了类之后其serialVersionUID会发生改变,也就是还原对象时会找不到其类型。有一个解决方法是将serialVersionUID放在类中,使其固定。

使用serialver工具可以查询某个类的serialVersionUID,再将其赋给类中的static final long serialVersionUID变量

public class Dog{
	static final long serialVersionUID=-3480159834908509L;
	//其它代码
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值