ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。 其writeObject 方法用于将对象写入流中。
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。其readObject方法用于从流读取对象。应该使用 Java 的安全强制转换来获取所需的类型。
一旦某个类实现了Serializable接口,则该类的对象就是可序列化的,程序可以通过如下两个步骤来序列化该对象。
1)创建一个ObjectOutputStream,这个输出流是一个处理流,所以必须建立在其他节点流的基础上。
2)调用ObjectOutputStream对象的writeObject方法输出可序列化对象。
下面程序定义了一个Person类,这个Person类就是一个普通Java类,只是实现了Serializable接口。
public class Person implements Serializable{ //属性 private String name; private int age; //构造器 Person(){} Person(String name, int age){ this.name = name; this.age = age; } //setter和getter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
下面程序使用ObjectOutputStream将一个Person对象写入磁盘文件。
public class WriteObject { public static void main(String[] args) { ObjectOutputStream oos = null; try{ //创建一个ObjectOutputStream输出流 oos = new ObjectOutputStream(new FileOutputStream("e:\\object.txt")); Person p = new Person("郭靖", 24); //将对象写入输出流 oos.writeObject(p); }catch(IOException e){ e.printStackTrace(); }finally{ try{ if(oos != null) oos.close(); }catch(IOException e){ e.printStackTrace(); } } } }
运行看到生产一个Person.txt文件,该文件内容就是Person对象。
如果要从二进制流中恢复Java对象,则需要使用反序列化。反序列化的步骤如下:
1)创建一个ObjectInputStream,这个输入流是一个处理流,所以必须建立在其他节点流的基础上。
2)调用ObjectInputStream对象的readObject方法读取流中的对象,该方法返回值是Object类型,一般要进行强制类型转换。
public class ReadObject { public static void main(String[] args) { ObjectInputStream ois = null; try{ //创建一个ObjectInputStream输入流 ois = new ObjectInputStream(new FileInputStream("e:\\object.txt")); //从输入流中读取一个Java对象,并将其强制转换成Person类 Person p = (Person)ois.readObject(); System.out.println("名字是:" + p.getName() + ",年龄:" + p.getAge()); }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(ois != null) ois.close(); }catch(IOException e){ e.printStackTrace(); } } } }
注意:
1)反序列化读取的仅仅是Java对象的数据,而不是Java类。因此采用反序列化恢复Java对象时,必须提供Java对象所属类的class文件,否则将会引发ClassNotFoundException。
2)反序列化机制无须通过构造器来初始化Java对象。
3)如果向文件中使用序列化机制写入了多个Java对象,使用反序列化机制恢复对象时必须按实际写入的顺序读取。
4)如果一个可序列化类有多个父类(包括直接或间接父类),则该类的所有父类要么是可序列化的,要么有无参数的构造器——否则会引发InvalidClassException异常。
因为当程序创建子类实例时,系统会隐式地为它的所有父类都创建实例(并建立和此子类实例的关联),当反序列化某个子类的实例时,反序列化机制需要恢复其关联的父类实例,恢复这些父类实例有两种方式:
a.使用反序列化机制。
b.使用父类无参数的构造器。
反序列化机制优先采用第一种机制。如果某个父类既不可序列化,则不能使用第一种机制;有没有提供无参数的构造器,则不可采用第二种机制,那么反序列化该子类实例时将抛出异常。