笔记:I/O流-对象序列化
Java
语言支持一种称为对象序列化(Object
Serialization)的非常通用的机制,可以将任何对象写入到流中,并在之后将其读回,首先需要支持对象序列化的类,必须继承与
Serializable
接口,该接口没有任何方法,只是对类起到标记的作用,然后使用
ObjectOutputStream
流来序列化对象,使用
ObjectInputStream
流来反序列化,示例代码如下:
- 对象类声明:
public class Employee implements Serializable {
private String name;
private String sex;
public
Employee() {}
public
Employee(String name, String sex) {this.name = name;
this.sex = sex;
}
// getter 和 setter 方法
}
public class Manager extends Employee {
private Employee secretary;
public
Manager(){}
public
Manager(String name, String sex) {super(name, sex);
}
// getter 和 setter 方法
}
- 创建对象实例:
Employee harry = new
Employee("Harry Hacker", "男");Manager boss = new
Manager("Carl Cracker", "女");boss.setSecretary(harry);
- 序列化到文件
ObjectOutputStream outputStream = null;try {
outputStream = new
ObjectOutputStream(new
FileOutputStream("serializableApp.dat"));outputStream.writeObject(boss);
} catch (FileNotFoundException ex) {ex.printStackTrace();
} finally {if (outputStream != null) {
outputStream.close();
}
} - 从文件反序列化
ObjectInputStream inputStream = null;
try {
inputStream = new
ObjectInputStream(new
FileInputStream("serializableApp.dat"));
Manager serializableBoss = (Manager) inputStream.readObject();
System.out.println("manager name is " + serializableBoss.getName() + " sex is "
+ serializableBoss.getSex() + " secretary is "
+ serializableBoss.getSecretary().getName());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
}
每个对象都用一个序列号保存的,对象序列化机制如下:
- 对于遇到的每一个对象引用都关联一个序列号
- 对于每一个对象,当第一次遇到时,保存器对象数据到流中
- 如果某个对象已经被保存过,那么只写出保存的序列号
- 对于流中的对象,在第一次遇到其序列号时,创建他,并使用流中数据来初始化他,然后记录这个顺序号和新对象之间的关联
- 当遇到对象引用另一个对象的序列号时,获取与这个序列号相关联的对象引用
某些数据域时不可以序列化的,例如,只对本地方法有意义的存储文件句柄或窗口句柄的整数值等,Java
拥有一种简单的机制来防止这种域被序列化,那就是将他们标记成
transient,如果被标记为不可序列化的类,也需要将其标记为
transient,瞬时域在对象序列化时总是被跳过,示例如下:
private transient Point2D.Double point;
- 修改默认的序列化机制
序列化机制单个的类提供了一种方式,去向默认的读写行为添加验证或任何其他想要的行为,可序列化类可以定义具体有如下签名的方法:
private
void
readObject(ObjectInputStream in)throws IOException,ClassNotFoundException;
private
void
writeObject(ObjectOutputStream out)throws IOException;
readObject
和
writeObject
方法只需要保存和加载本类的数据域,而不需要关注基类(超类)数据和任何其他类的信息,实现给方法的具体示例如下:private
void
readObject(ObjectInputStream in)throws IOException, ClassNotFoundException {
// 读取序列化字段数据
in.defaultReadObject();
// 其他数据校验或者序列化
}
private
void
writeObject(ObjectOutputStream out)throws IOException{
// 写入序列化字段数据
out.defaultWriteObject();
// 其他数据校验或者序列化
}
除了可以使用readObject
和
writeObject方法来保存和恢复对象数据外,类还可以定义他自己的机制,类需要实现
Externalizable
接口,该接口定义了两个方法:public
void
readExternal(ObjectInput in)
throws IOException, ClassNotFoundException;
public
void
writeExternal(ObjectOutput out)throws IOException ;
这些方法对包括超类数据在内的整个对象的存储和恢复负全责,而序列化机制在流中仅仅只是记录该对象所属的类,示例代码如下:
- 基类代码:
public
void
writeExternal(ObjectOutput out) throws IOException {out.writeUTF(this.name);
out.writeUTF(this.sex);
}
public
void
readExternal(ObjectInput in) throws IOException, ClassNotFoundException {this.name = in.readUTF();
this.sex = in.readUTF();
}
- 子类代码:
@Override
public
void
readExternal(ObjectInput in) throws IOException, ClassNotFoundException {super.readExternal(in);
this.secretary = new
Employee();
this.secretary.readExternal(in);}
@Override
public
void
writeExternal(ObjectOutput out) throws IOException {super.writeExternal(out);
this.secretary.writeExternal(out);
}
- 序列化单例和类型安全的枚举
在序列化和反序列化时,如果目标对象时唯一的,使用默认的序列化机制时不适用的,因为默认的序列化机制,即使构造器时私有的,序列化机制也可以创建新的对象,因此在进行==(比较)时将失败,为了解决整个问题需要定义一个名称为 readResolve的特殊方法,在对象被序列化之后就会调用他,返回一个对象,而该对象之后会称为 readObject 的返回值,示例代码如下:
public class Orientation implements Serializable {
public static final Orientation HORIZONTAL = new
Orientation(1);public static final Orientation VERTICAL = new
Orientation(2);
private
int value;
private
Orientation(int value) {this.value = value;
}
protected Object readResolve() throws ObjectStreamException {
if (value == 1) {
return HORIZONTAL;
}
if (value == 2) {
return VERTICAL;
}
return null;
}
}
- 版本管理
无论类的定义产生了什么样的变化,他的SHA指纹也会跟着变化,而我们知道对象流拒绝读入具有不同指纹的对象,但是,类可以表明他对其早期版本保持兼容,在类的所有较新的版本都必须把
serialVersionUID
常量定义与最初版本的指纹相同,如果一个类具有名为
serialVersionUID
的静态数据成员,就不需要在人工的计算其指纹,而只需直接使用整个值,示例如下:public class Employee implements Serializable, Externalizable {
public static final
long serialVersionUID = -2349238498234324L;}
如果类只有方法产生了变化,那么在读入新对象数据时是不会有任何问题的,如果是数据域产生了变化,那么就可能会有问题,常见情况如下:
- 如果数据域之间名字匹配而类型不匹配,那么对象流不会进行类型转换,因此不兼容
- 如果流中的对象具有当前版本中所没有的数据域,那么对象流会忽视这些额外的数据
- 如果当前版本具有在流化对象中所没有的数据域,那么这些新增加的域将被设置成他们的默认值(对象是null、数字为
0,布尔类型为
false)
笔记:I/O流-对象序列化的更多相关文章
- Java开发笔记(九十)对象序列化及其读写
有些时候,开发者想把程序运行过程中的数据临时保存到文件,可是前面介绍的字符流和字节流,要么用来读写文本字符串,要么用来读写字节数组,并不能直接保存某个对象信息,因为对象里面包括成员属性和成员方法,单就 ...
- Java学习笔记——IO操作之对象序列化及反序列化
对象序列化的概念 对象序列化使得一个程序可以把一个完整的对象写到一个字节流里面:其逆过程则是从一个字节流里面读出一个事先存储在里面的完整的对象,称为对象的反序列化. 将一个对象保存到永久存储设备上称为 ...
- java学习笔记之IO编程—对象序列化
对象序列化就是将内存中保存的对象以二进制数据流的形式进行处理,可以实现对象的保存或网络传输. 并不是所有的对象都可以被序列化,如果要序列化的对象,那么对象所在的类一定要实现java.io.Serial ...
- JAVA笔记12__字节、字符缓冲流/打印流/对象流/
/** * !!:以后写流的时候一定要加入缓冲!! * 对文件或其它目标频繁的读写操作,效率低,性能差. * 缓冲流:好处是能更高效地读写信息,原理是将数据先缓冲起来,然后一起写入或读取出来. * * ...
- javaSE学习笔记(15) ---缓冲流、转换流、序列化流
javaSE学习笔记(15) ---缓冲流.转换流.序列化流 缓冲流 昨天复习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流.比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化 ...
- I/O 流和对象序列化
一.I/O 流(java 如何实现与外界数据的交流) 流定义: 任何有能力产出数据的数据源对象或者有能力接收数据的数据源对象.他屏蔽了实际的I/O设备处理数据的细节. 1.Input/Output:指 ...
- JAVA基础学习day22--IO流四-对象序列化、管道流、RandomAccessFile、DataStream、ByteArrayStream、转换流的字符编码
一.对象序列化 1.1.对象序列化 被操作的对象需要实现Serializable接口 1.2.对象序列化流ObjectOutputStream与ObjectInputStream ObjectInpu ...
- 疯狂Java学习笔记(84)----------大约 Java 对象序列化,你不知道 5 事
几年前,.当一个软件团队一起用 Java 书面申请.我认识比一般程序猿多知道一点关于 Java 对象序列化的知识所带来的优点. 关于本系列 您认为自己懂 Java 编程?其实,大多数程序猿对于 Jav ...
- Java IO(Properties/对象序列化/打印流/commons-io)
Java IO(Properties/对象序列化/打印流/commons-io) Properties Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载. ...
随机推荐
- HDP2.0.6+hadoop2.2.0+eclipse(windows和linux下)调试环境搭建
花了好几天,搭建好windows和linux下连接HDP集群的调试环境,在此记录一下 hadoop2.2.0的版本比hadoop0.x和hadoop1.x结构变化很大,没有eclipse-hadoop ...
- (2018干货系列一)最新Java学习路线整合
怎么学Java Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征. 话不多说,直接上干货: ...
- 用Node.JS+MongoDB搭建个人博客(万众期待的router.js)(四)
万众期待的router.js,是我现在最想写的一个博客.因为他包含了整个个人博客的精髓.在这里,所有的请求配置,返回的参数等等所做的业务逻辑都在这个文件里实现. 我会详细说明这些代码的作用,所以这篇博 ...
- 【前端】Vue2全家桶案例《看漫画》之七、webpack插件开发——自动替换服务器API-URL
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_7.html 项目github地址:https://github.com/shamoyuu/ ...
- R语言︱排序问题
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 数据排序 1.sort(),rank(),or ...
- Netty的并发编程实践5:不要依赖线程优先级
当有多个线程同时运行的时候,由线程调度器来决定哪些线程运行.哪些等待以及线程切换的时间点,由于各个操作系统的线程调度器实现大相径庭,因此,依赖JDK自带的线程优先级来设置线程优先级策略的方法是错误和非 ...
- raid功能中spanning和striping模式有什么区别?
RAID 0 又称为Stripe(条带化,串列)或Striping 它代表了所有RAID级别中最高的存储性能.RAID 0提高存储性能的原理是把连续的数据分散到多个磁盘上存取,这样,系统有数据请求就可 ...
- DataTable复制数据,深度复制
/**/ /// <summary> /// 复制数据,深度复制 /// </summary> /// <param name="dataSourceRow&q ...
- SonarQube和Maven的集成
1.1. SonarQube简介 SonarQube是一款免费用于代码质量管理的开源平台,用于管理源代码的质量,可以从七个维度检测代码质量通过插件形式,可以支持包括java,C#,C/C++,PL/S ...
- 如何用python和苹果Turicreate学习框架来识别图像?
大多数人听到深度学习,都会望而却步,因为会觉得很难,在这个人工智能飞速进步的时代,我也来抓一下时代的尾巴~ 两周前,我开始接触到python和Turicreate框架,经过不懈的努力,终于有所收获,特 ...