假如有两个类,分别是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;
}