假如有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); },这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个空间,而对象a同时在内存中存在两份,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所希望的!
以下序列化机制的解决方案:
1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)
2.当要保存一个对象时,先检查该对象是否被保存了。
3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保存该对象
但不是每一个类都能序列化,例如java.awt.geom包中的Point2D.Double类就是不可序列化的,因为该类没有实现Serializable接口java.io包有两个序列化对象的类。ObjectOutputStream负责将对象写入字节流,ObjectInputStream从字节流重构对象。
API描述
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。
我们先了解ObjectOutputStream类吧。ObjectOutputStream类扩展DataOutput接口。
writeObject()方法是最重要的方法,用于对象序列化。如果对象包含其他对象的引用,则writeObject()方法递归序列化这些对象。每个 ObjectOutputStream维护序列化的对象引用表,防止发送同一对象的多个拷贝。(这点很重要)下面,让我们从例子中来了解ObjectOutputStream这个类)~#U2F'{3}#l bbs.spoto.net9k({%k%r3{7u,?+p1q // 序列化 today's date 到一个文件中. 3c7c*`!h-H2W |&l FileOutputStream f = new FileOutputStream("tmp"); 1M;E&R,f.o1A8[+w ObjectOutputStream s = new ObjectOutputStream(f); s.writeObject("Today"); s.writeObject(new Date()); s.flush(); ,f9Q5`2[:t Y ObjectInputStream这个类。它与ObjectOutputStream相似。它扩展DataInput接口。 ObjectInputStream中的方法镜像DataInputStream中读取Java基本数据类型的公开方法。readObject()方法从字节流中反序列化对象。每次调用readObject()方法都返回流中下一个Object。对象字节流并不传输类的字节码,而是包括类名及其签名。 readObject()收到对象时,JVM装入头中指定的类。如果找不到这个类,则readObject()抛出 ClassNotFoundException,如果需要传输对象数据和字节码,则可以用RMI框架。ObjectInputStream的其余方法用于定制反序列化过程。:h2z(J+h,d;S5R 例子如下:IT雏鹰部落(N,V1M&~$w //从文件中反序列化 string 对象和 date 对象 bbs.spoto.net)/1_8[6Z H8V5| FileInputStream in = new FileInputStream("tmp"); ObjectInputStream s = new ObjectInputStream(in); String today = (String)s.readObject(); Date date = (Date)s.readObject(); ;w&d'}+n"I5r8o&c:R @
例子,来自开源中国客户端代码
/** * 保存对象 * @param ser * @param file * @throws IOException */ //保存对象就是序列化 public boolean saveObject(Serializable ser, String file) { FileOutputStream fos = null; ObjectOutputStream oos = null; try{ fos = openFileOutput(file, MODE_PRIVATE); oos = new ObjectOutputStream(fos); oos.writeObject(ser); oos.flush(); return true; }catch(Exception e){ e.printStackTrace(); return false; }finally{ try { oos.close(); } catch (Exception e) {} try { fos.close(); } catch (Exception e) {} } } /** * 读取对象 * @param file * @return * @throws IOException */ //反序列化 public Serializable readObject(String file){ if(!isExistDataCache(file)) return null; FileInputStream fis = null; ObjectInputStream ois = null; try{ fis = openFileInput(file); ois = new ObjectInputStream(fis); return (Serializable)ois.readObject(); }catch(FileNotFoundException e){ }catch(Exception e){ e.printStackTrace(); //反序列化失败 - 删除缓存文件 if(e instanceof InvalidClassException){ File data = getFileStreamPath(file); data.delete(); } }finally{ try { ois.close(); } catch (Exception e) {} try { fis.close(); } catch (Exception e) {} } return null; }