在 Java 中,ObjectInputStream 类(java.io.ObjectInputStream)可让您从 InputStream 中读取 Java 对象,而不仅仅是原始字节。将 InputStream 封装在 ObjectInputStream 中,然后就可以从中读取对象。
注意:
(1)读取的字节必须是有效的、序列化的 Java 对象,否则读取对象将失败。
(2) 通常,你将使用 ObjectInputStream 来读取由 ObjectOutputStream 写入(序列化)的对象。
以下是一个 ObjectInputStream 示例:
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("object.data")); MyClass object = (MyClass) objectInputStream.readObject(); //... objectInputStream.close();
注意,要使这个 ObjectInputStream 示例有效,你读取的对象必须是 MyClass 的实例,并且必须已通过 ObjectOutputStream 序列化到文件“object.data ”中。
在序列化和反序列化对象之前,对象的类必须实现 java.io.Serializable 接口。
Serializable 是一个标记接口(Marker Interface),标记接口的特点是接口内部没有定义任何方法。其存在的意义在于给类打上一个 “标记”,告知 Java 虚拟机(JVM)这个类的对象可以被序列化。
Serializable 接口源码:
public interface Serializable { }
序列化指的是把 Java 对象转换为字节序列的过程。这些字节序列能够被存储在文件中,也可以通过网络进行传输。
与序列化相反,它是把字节序列重新转换为 Java 对象的过程。
注意,我们可以通过 ObjectInputStream 类实现反序列化,通过 ObjectOutputStream 类实现序列化。
下面将展示一个将 ObjectInputStream 与 ObjectOutputStream 结合使用的示例。演示如何对 Java 对象进行序列化和反序列化,如下:
package com.hxstrive.java_io; import java.io.*; public class ObjectInputStreamExample { public static void main(String[] args) throws Exception { // 序列化 try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("object.data"))) { Person person = new Person(1, "张三"); out.writeObject(person); } // 反序列化 try(ObjectInputStream in = new ObjectInputStream(new FileInputStream("object.data"))) { Person person = (Person)in.readObject(); System.out.println(person); // 输出:Person{id=1, name='张三'} } } // 实现了 Serializable 标记接口 static class Person implements Serializable { private int id; private String name; public Person(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + '}'; } } }
上面示例,首先创建了一个与 FileOutputStream 相连的 ObjectOutputStream,接着创建一个 Person 对象并将其写入 ObjectOutputStream,即 object.data 文件。
然后,创建了一个与 ObjectOutputStream 连接到相同文件的 ObjectInputStream,并且从 ObjectInputStream 中读入一个对象,并将其转换为 Person 对象,最后将读入 Person 对象的值打印到 控制台。
当你完成从 ObjectInputStream 读取数据的操作后,务必牢记将其关闭。值得注意的是,关闭 ObjectInputStream 时,与之关联的用于读取数据的 InputStream 实例也会随之关闭。
若要关闭 ObjectInputStream,只需调用它的 close() 方法即可。如下:
objectInputStream.close();
您还可以使用 Java 7 中引入的 try-with-resources 结构,如下:
InputStream input = new FileInputStream("object.data"); try(ObjectInputStream objectInputStream = new ObjectInputStream(input)){ Person personRead = (Person) objectInputStream.readObject(); //... }
注意,此处不再有任何显式的 close() 方法调用,因为 try-with-resources 结构已自动处理资源关闭问题。
另外,首个 FileInputStream 实例并非在 try-with-resources 代码块中创建,这意味着该代码块不会自动关闭此 FileInputStream 实例。不过,当 ObjectInputStream 关闭时,它会同步关闭其所读取的 InputStream 实例。所以,FileInputStream 实例会在 ObjectInputStream 关闭时一同被关闭。