java序列化与反序列化总结
来源:互联网 发布:js点击按钮隐藏div 编辑:程序博客网 时间:2024/05/29 09:31
1 含义
序列化:把java对象转变成一组字节数组。
反序列化:从一组字节流中恢复成一个java对象。
注意:序列化过程仅保存对象的成员变量。
2、使用时机
1)需要将内存中的对象”持久化”的存储在硬盘上(文件或数据库中)
2)需要网络通信时:先将对象序列化为一串二进制字节流,再进行传输;接收端,先接收二进制流,再从中反序列化出对象。
3、java中实现序列化的前提
3.1 两个重要的类
ObjectOutputStream
对象输出流,即通过该类将对象序列化并输出到指定的输出流中。
构造:
ObjectOutputStream(OutputStream out)
重要方法:
void writeObject(Object obj),序列化obj对象并写入到输出流中
ObjectInputStream
对象输入流,从一个输入流中读取字节序列,并反序列化为一个对象。
构造:
ObjectInputStream(InputStream in)
重要方法:
Object readObject(),反序列化出对象,并返回。3.2 两个重要的接口
Serializable
该接口是一个标记接口,也就是空接口,没有任何的方法。
只有实现了Serializable接口的类才能被java的序列化机制处理,否则会抛出异常。
Externalizable
实现了Externalizable接口的类也能被序列化。
Externalizable接口继承自Serializable接口。
Externalizable接口有两个重要方法:
void readExternal(ObjectInput in)
void writeExternal(ObjectOutput out)
实现了Externalizable接口的类,必须override该接口的两个方法。在序列化对象的时候,java会调用writeExternal()方法来序列化对象;在反序列化时,java会调用readExternal()方法来恢复对象。即是说,通过实现Externalizable接口来进行序列化时,我们可以手动控制对象的哪些成员能被序列化,哪些成员不需要被序列化,更加灵活。
4、java序列化实例
注意:对象序列化是基于字节流的,应该使用InputStream和OutputStream,不能使用基于字符的Reader和Writer。
4.1 实现Serializable接口并采用默认的序列化方式
class Person implements Serializable{private int age;private int height;private String name;private transient String gender;public Person(int age, int height, String name, String gender){this.age = age;this.height = height;this.name = name;this.gender = gender;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("年龄:" + age + ", 身高:" + height + ", 姓名:" + name+ ", 性别:" + gender);return sb.toString();}}public static void main(String[] args) {try {// 序列化对象ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.txt"));out.writeObject(new Person(20, 170, "赵李", "男"));out.flush();out.close();// 反序列化对象ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.txt"));Person p = (Person)in.readObject();System.out.println(p.toString());in.close();} catch (ClassNotFoundException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}}
输出:
年龄:20, 身高:170, 姓名:赵李, 性别:null
分析:
上述代码对Person对象的非transient成员变量进行了序列化与反序列化。4.2 实现Serializable接口并采用自定义的序列化方式
按4.1中的代码,在Person类中增加了两个私有方法writeObject()和readObject(),main()函数不变:
class Person implements Serializable{private int age;private int height;private String name;private transient String gender;public Person(int age, int height, String name, String gender){this.age = age;this.height = height;this.name = name;this.gender = gender;}// 自定义序列化private void writeObject(ObjectOutputStream out) throws IOException{out. defaultWriteObject ();// 手动序列化transient成员out.writeObject(gender);}// 自定义反序列化private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException{in.defaultReadObject();// 手动反序列化transient成员gender = (String)in.readObject();}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("年龄:" + age + ", 身高:" + height + ", 姓名:" + name+ ", 性别:" + gender);return sb.toString();}}
输出:
年龄:20, 身高:170, 姓名:赵李, 性别:男
分析:
看一下堆栈调用:在该自定义的序列化方式中,main()中的ObjectOutputStream.writeObject()方法通过一系列调用,最后会调用Person.writeObject()方法序列化Person对象,上图可知,应该是通过反射机制来调用Person.writeObject()处理。
反序列化同理,ObjectInputStream.readObject()最终调用Person.readObject()完成反序列化过程。
在Person自定义的两个私有方法中,可以手动序列化与反序列化transient成员,如上例所示。
疑问:
Person类中若定义为 public void writeObject(ObjectOutputStream out)
或 public voidreadObject(ObjectInputStream in),
则不会调用这两个自定义方法,即是说必须声明为private方法才能被调用,为什么?4.3 实现Externalnalizable接口并采用自定义的序列化方式
Person类实现Externalnalizable接口,覆写readExternal()和writeExternal()方法实现自定义的序列化和反序列化,main()函数不变,如下:
class Person implements Externalizable{private int age;private int height;private String name;private transient String gender;public Person() {}public Person(int age, int height, String name, String gender){this.age = age;this.height = height;this.name = name;this.gender = gender;}// 序列化实现@Overridepublic void writeExternal(ObjectOutput out) throws IOException {// 手动序列化每个成员out.writeObject(age);out.writeObject(height);out.writeObject(name);out.writeObject(gender); // 可以序列化transient成员}// 反序列化实现@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {this.age = (int)in.readObject();this.height = (int)in.readObject();this.name = (String)in.readObject();this.gender = (String)in.readObject();}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("年龄:" + age + ", 身高:" + height + ", 姓名:" + name+ ", 性别:" + gender);return sb.toString();}}
输出:
年龄:20, 身高:170, 姓名:赵李, 性别:男
分析:
在该种序列化方式中,main()中的ObjectOutputStream.writeObject()最后会调用Person. writeExternal()方法完成序列化过程,反序列化过程类似。
在Person.writeExternal()中,通过对Person成员变量的依次写入完成序列化过程,手动控制每个成员是否需要被序列化,更为灵活。在Person.readExternal()中,按照成员序列化的顺序,依次反序列化出每个成员,完成Person对象的反序列化过程。
注意:
通过实现Externalnalizable接口的序列化方式,必须提供被序列化对象的无参构造函数,上例中,即必须声明 public Person() {} 才行,否则会报如下错误
5 使用java序列化机制需要注意的几点
5.1 serialVersionUID
该字段用来保证对象在序列化和反序列化过程中的一致性,即是说,只有相同serialVersionUID值的同类对象才能相互序列化和反序列化,若有两个类,其成员和方法完全形同,但其serialVersionUID不同,是无法相互序列化和反序列化的。
若无特殊要求,serialVersionUID取默认值即可,即:
private static finallong serialVersionUID = 1L;
5.2 static、transient成员
static成员属于某个类,而非某个特定的对象,序列化机制会忽略static成员,不会保存static成员的状态。
默认的序列化机制也会忽略transient成员,但自定义的序列化方式可以手动序列化和反序列化transient成员,如上述的例子所示。
5.3 序列化中的包含问题
若一个被序列化的对象中包含其他对象,则被包含的对象也会被序列化。可以理解为java的序列化机制是一个”深拷贝”,它会将待序列化对象的整个对象图全部序列化掉。
5.4 序列化中的继承问题
若父类已实现序列化,则子类自动序列化,不需要显示实现Serializable接口。
若父类未实现序列化,但子类实现了序列化,序列化某个子类对象,再反序列化后,子类对象中某些继承自在父类中定义的成员变量,其值与序列化前的值可能不同。因为父类没有实现序列化,在反序列化时,java会先调用父类的无参构造,再调用子类的构造函数。那些在父类中定义的成员变量,其值是调用父类无参构造后的值,与序列化前实际的值可能有差异。
建议在使用java的序列化与反序列化时,尽s量避免类继承。
6 参考文章
http://blog.csdn.net/jiangwei0910410003/article/details/18989711/#t7
http://blog.csdn.net/wangloveall/article/details/7992448/
http://blog.csdn.net/endlu/article/details/51178143
http://www.oschina.net/translate/serialization-in-java?lang=chs&page=1#
http://www.2cto.com/kf/201405/305380.html- java序列化与反序列化总结
- java对象序列化与反序列化总结
- java 序列化 Serializable 与 反序列化 总结
- java序列化与反序列化总结
- java序列化与反序列化总结
- Java序列化与反序列化的总结
- Java序列化与反序列化总结
- java 序列化与反序列化总结
- java序列化与反序列化总结
- Java常见序列化与反序列方法总结
- Java常见序列化与反序列方法总结
- java序列化与反序列化
- java序列化与反序列化
- java序列化与反序列化
- java序列化与反序列化
- Java序列化与反序列化
- Java序列化与反序列化
- java 序列化 与 反序列化
- 1、ThinkPHP源码学习-致命错误捕获及自定义错误输出
- Android7.0中文文档(API)-- TextView
- jsemu
- Android Lint官方静态代码检查工具
- 计算机百科
- java序列化与反序列化总结
- 简易版WireShark实现-效果
- 函数和string对象
- 原生js对dom点的操作
- ECMAScript 2015官方文档翻译(一)
- 使用Excle生成SQL语句总结
- [Maven]引入自定义Jar包(在maven仓库找不到的那种)
- 如何在百度地图上标注宾馆饭店(矢量点标注)并导出为图片
- 在网页中调出QQ