Java I/O系统学习系列五:Java序列化机制
在Java的世界里,创建好对象之后,只要需要,对象是可以长驻内存,但是在程序终止时,所有对象还是会被销毁。这其实很合理,但是即使合理也不一定能满足所有场景,仍然存在着一些情况,需要能够在程序不运行的情况下保持对象,所以序列化机制应运而生。
1. 为什么要有序列化
简单来说序列化的作用就是将内存中的对象保存起来,在需要时可以重建该对象,并且重建后的对象拥有与保存之前的对象所拥有的信息相同。在实际应用中,对象序列化常会用在如下场景:
- RPC框架的数据传输;
- 对象状态的持久化保存;
也许你会觉得,要达到这种持久化的效果,我们直接将信息写入文件或数据库也可以实现啊,为什么还要序列化?这是一个好问题,试想如果我们采用前面所述的方法,在序列化对象和反序列化恢复对象时,我们必须考虑如何完整的保存和恢复对象的信息,这里面会涉及到很多繁琐的细节,稍加不注意就可能导致信息的丢失。如果能够有一种机制,只要将一个对象声明为是“持久性”的,就能够为我们处理掉所有细节,这样岂不是很方便,这就是序列化要做的事情。Java已经将序列化的概念加入到语言中,本文的关于序列化的所有例子都是基于Java的。
Java提供的原生序列化机制功能强大,有其自己的一些特点:
- 序列化处理非常简单,只需将对象实现Serializable接口即可;
- 能够自动弥补不同操作系统之间的差异,即可以在运行Windows系统的计算机上创建一个对象,将其序列化,然后通过网络将它发送给一台运行Unix系统的计算机,然后在那里准确地重新组装,不必担心数据在新的机器上表示会不同;
- 对象序列化不仅会保存对象的“全景图”,而且能够追踪对象内所包含的所有引用,并保存那些对象;接着又能对对象内包含的每个这样的引用进行追踪,依此类推;
- 对象序列化保存的是对象的”状态”,即它的成员变量,所以对象序列化并不会处理类中的静态变量;
2. 序列化机制的使用
Java的对象序列化机制是将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
要序列化一个对象,首先要创建一个OutputStream对象,然后将其封装在一个ObjectOutputStream对象内,接着只需调用writeObject()方法即可将对象序列化,并将序列化后的字节序列发送给OutputStream。要将一个序列还原为一个对象,则需要将一个InputStream封装在ObjectInputStream内,然后调用readObject(),该方法会返回一个引用,它指向一个向上转型的Object,必须向下转型才能直接使用。
我们来看一个例子,如何序列化和反序列化对象。
public class Worm implements Serializable{ private static Random rand = new Random(47); private Data[] d = { new Data(rand.nextInt(10)), new Data(rand.nextInt(10)), new Data(rand.nextInt(10)) }; private Worm next; private char c; public Worm(int i, char x){ System.out.println("Worm constructor: " + i); c = x; if(--i > 0){ next = new Worm(i,(char)(x + 1)); } } public Worm(){ System.out.println("Default constructor"); } public String toString(){ StringBuilder result = new StringBuilder(":"); result.append(c); result.append("("); for(Data dat : d){ result.append(dat); } result.append(")"); if(next != null){ result.append(next); } return result.toString(); } public static void main(String[] args) throws ClassNotFoundException, IOException{ Worm w = new Worm(6,'a'); System.out.println("w = " + w); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out")); out.writeObject("Worm storage\n"); out.writeObject(w); out.close(); ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out")); String s = (String)in.readObject(); Worm w2 = (Worm)in.readObject(); System.out.println(s + "w2 = " + w2); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out2 = new ObjectOutputStream(bout); out2.writeObject("Worm storage\n"); out2.writeObject(w); out2.flush(); ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray())); s = (String)in2.readObject(); Worm w3 = (Worm)in2.readObject(); System.out.println(s + "w3 = " + w3); } } class Data implements Serializable{ private int n; public Data(int n){this.n = n;} public String toString(){return Integer.toString(n);} }
输出结果如下: