ObjectOutputStream和ObjectInputStream
--ObjectOutputStream
ObjectInputStream 类恢复以前使用 ObjectOutputStream 类序列化后的基本类型数据和对象。
ObjectOutputStream 和 ObjectInputStream 分别利用 FileOutputStream 和 FileInputStream 能支持应用程序实现对象图象的稳定存储。
ObjectInputStream 可用于恢复以前序列化过的对象。另外其它一些情况也使用此类,诸如使用一个 Socket 在主机间传递对象时,
或在远程通讯系统中为实现参数和参变量的通讯而进行对象传递时。
ObjectInputStream 保证从流中创建的图象中的所有对象的类型与 Java 虚拟机中出现的类匹配。使用标准机制按需装载相应类。
只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流中读取。使用 readObject 方法从该流中
读取一个对象。 Java 的安全造型应该用于获取期望类型。在 Java 中, 串和数组都是对象且可当作是序列化过程中的对象。
读取时,它们需要转换为所需类型。
另外基类型也可使用 DataInput 中的正确方法从该流中读取。
对象的缺省逆序列化机制将每个域的内容恢复为它被写入时的值和类型。逆序列化过程中忽略申明为暂时的或静态的域。
对其它对象的引用促使那些对象必须从流中读取。使用引用共享机制正确地恢复对象的图象。逆序列化时总是分配新对象,
防止重写已存在的对象。
读取一个对象同运行一个新对象的构造子类似。为该对象分配的内存初始化为空(NULL)。为非序列化类调用无参构造子,
然后将序列化类的域从该流中恢复,恢复从最接近 java.lang.object 的序列化对象开始,到指定对象结束。
例如读取在示例中写入 ObjectOutputStream 中的流:
FileInputStream istream = new FileInputStream("t.tmp");
ObjectInputStream p = new ObjectInputStream(istream);
int i = p.readInt();
String today = (String)p.readObject();
Date date = (Date)p.readObject();
istream.close();
类通过实现 java.io.Serializable 或 java.io.Externalizable 接口来控制它们的序列化。
实现序列化接口可以使对象能保存和恢复它的完整状态,可以使类在写入流和从流中读取的期间内进行改进。
它自动地遍历对象间的引用,保存和恢复完整图象。在序列化和逆序列化处理过程中需要特定句柄的可序列化类,
必须实现如下这两个方法:
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException;
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
利用 writeObjectmethod 方法将一个特殊类的对象的状态写入某流后,相应的 readObject 方法将负责读取和恢复这些数据。
此方法不必关心状态是属于它的父类还是子类。 从 ObjectInputStream 读取数据恢复单个域的状态,并将之赋给该对象的恰当域。
使用 DataInput 方法读取基本数据类型。
序列化操作对没有实现 java.io.Serializable 接口的对象,不读取或分配它的域值。非序列化对象的子类可以是序列化的。
在这种情况下,非序列化类必须有一个无参构造子,使它的域能使用此构造子完成初始化。 在此情况下,
子类负责保存和恢复非序列化类的状态。通常情况父类的域是可存储的(公有的、包或保护的),
或存在用于恢复它的状态的可使用的获取或设置方法。
ObjectInputStream 能获取逆序列化一个对象期间出现的任一异常,一旦出现异常,则放弃读过程。
实现外部接口可以使对象完全控制此对象序列化形式的内容和格式。
调用外部接口的方法:writeExternal 和 readExternal 保存和恢复对象状态。当一个类实现了这些方法时,
它们就能使用 ObjectOutput 和 ObjectInput 方法的所有方法写入或读取它们自己的状态。对象负责管理它出现的相应版本。
ObjectOutputStream
public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants
类 ObjectOutputStream 将 Java 对象中的基本数据类型和图元写入到一个 OutputStream 对象中。可使用 ObjectInputStream 读取这些对象。
另外使用此流对应的文件能存储这些对象。如果该流是一个网络通讯流,则在另一台主机或另一个处理机上可重建这些对象。
只有支持 java.io.Serializable 接口的对象才能被写入该流。对每个可序列化的对象进行编码,包括相应类的名称和标记,
对象的属性和数组值,以及初始化对象时引用的任何其它对象等。
使用 writeObject 将一个对象写入该流。任一对象,包括串和数组,均采用 writeObject 方法被写入。
也能将多个对象或基类型对象写入此流。反过来,必须以这些对象被写入的相同类型和相同顺序,
从相应的 ObjectInputstream 流中读回这些对象。
基类型也可使用 DataOutput 中的正确方法写入此流。串对象也可使用 writeUTF 方法写入。
一个对象的缺省序列化机制将写入对象的类,类标记和所有的非暂时的和非静态的属性值。
其它对象(除暂时的或静态的属性)的引用也将促使以上这些对象被写入。 使用共享机制,对单一对象的多次引用进行编码,
以至对象的图元能被存储为与它原来写入时有相同的形状。
例如写入一个对象,此对象能从 ObjectInputStream 中读出:
FileOutputStream ostream = new FileOutputStream("t.tmp");
ObjectOutputStream p = new ObjectOutputStream(ostream);
p.writeInt(12345);
p.writeObject("Today");
p.writeObject(new Date());
p.flush();
ostream.close();
在序列化处理过程中需要特定句柄的类,必须使用如下这些恰当的标记实现特定的方法:
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException
writeObject 方法负责写特定类的对象的状态,以使相应的 readObject 方法能存储它。
此方法不必关心写入对象的父类或子类的状态。使用 writeObject 方法或基本类型支持的 DataOutput
方法将每个域的状态保存到 ObjectOutputStream 中。
序列化操作不能输出没有实现 java.io.Serializable 接口的任一对象的域。非序列化对象的子类可以是序列化的。
在这种情况下,非序列化类必须有一个无参构造子,使它的域能被初始化。 在此情况下,子类负责保存和恢复非序列化类的状态。
通常情况父类的域是可存储的(公有的、包或保护的),或存在用于恢复它的状态的可使用的获取或设置方法。
实现抛出 NotSerializableException 异常的 writeObject 和 readObject 方法能阻止一个对象的序列化。
ObjectOutputStream 将获取这个异常,并放弃这个序列化过程。实现外部接口可以使对象完全控制此对象序列化形式的内容和格式。
调用外部接口的方法:writeExternal 和 readExternal 保存和恢复对象状态。当一个类实现了这些方法时,
它们就能使用 ObjectOutput 和 ObjectInput 方法的所有方法写入或读取它们自己的状态。对象负责管理它出现的相应版本。
import java.io.*;
import java.util.*;
public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password;
Logon(String name, String pwd) {
username = name;
password = pwd;
}
public String toString() {
String pwd = (password == null) ? "(n/a)" : password;
return "logon info: \n " + "username: " + username + "\n date: " + date + "\n password: " + pwd;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Logon a = new Logon("Morgan", "morgan83");
System.out.println( "logon a = " + a);
ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Logon.out"));
o.writeObject(a);
o.close();
int seconds = 5;
long t = System.currentTimeMillis() + seconds * 1000;
while(System.currentTimeMillis() < t) ;
ObjectInputStream in = new ObjectInputStream( new FileInputStream("Logon.out"));
System.out.println( "Recovering object at " + new Date());
a = (Logon)in.readObject();
System.out.println("logon a = " + a);
}
}
类Logon是一个记录登录信息的类,包括用户名和密码。首先它实现了接口Serializable,这就标志着它可以被序列化。
之后再main方法里ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("Logon.out"));
新建一个对象输出流包装一个文件流,表示对象序列化的目的地是文件Logon.out。然后用方法writeObject开始写入。
想要还原的时候也很简单ObjectInputStream in = new ObjectInputStream( new FileInputStream("Logon.out"));
新建一个对象输入流以文件流Logon.out为参数,之后调用readObject方法就可以了。