Java ObjectInputStream 类
最后修改时间:2025 年 4 月 16 日
java.io.ObjectInputStream
类反序列化之前使用 ObjectOutputStream
写入的原始数据和对象。它从其序列化形式重建对象。该类实现了 ObjectInput
和 ObjectStreamConstants
接口。
ObjectInputStream
从底层输入流读取序列化数据。它处理对象图、循环引用和类版本控制。该类提供了从流中读取原始类型、对象和数组的方法。
ObjectInputStream 类概述
ObjectInputStream
扩展了 InputStream
并实现了对象反序列化。关键方法包括读取原始类型、对象以及通过 readObject
进行自定义反序列化。该类维护处理对象引用的状态。
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants { public ObjectInputStream(InputStream in) throws IOException; public final Object readObject() throws IOException, ClassNotFoundException; public int read() throws IOException; public int read(byte[] buf, int off, int len) throws IOException; public boolean readBoolean() throws IOException; public byte readByte() throws IOException; public char readChar() throws IOException; public double readDouble() throws IOException; public float readFloat() throws IOException; public int readInt() throws IOException; public long readLong() throws IOException; public short readShort() throws IOException; public String readUTF() throws IOException; public Object readUnshared() throws IOException, ClassNotFoundException; public void defaultReadObject() throws IOException, ClassNotFoundException; public void close() throws IOException; }
上面的代码展示了 ObjectInputStream
提供的关键方法。这些方法允许从序列化流中读取原始类型和对象。该类自动处理对象重建和引用解析。
创建 ObjectInputStream
ObjectInputStream 是通过将其包装在另一个 InputStream
周围来创建的。如果流头无效,构造函数可能会抛出 IOException
。完成操作后始终关闭流以释放资源。
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { try { // Create from FileInputStream FileInputStream fileStream = new FileInputStream("objects.dat"); ObjectInputStream objectStream = new ObjectInputStream(fileStream); System.out.println("ObjectInputStream created successfully"); // Always close streams objectStream.close(); } catch (IOException e) { System.err.println("Error creating ObjectInputStream: " + e.getMessage()); } } }
此示例演示了 ObjectInputStream
的基本创建。流被包装在从文件读取的 FileInputStream
周围。错误处理很重要,因为构造函数可能会抛出 IOException
。
读取原始类型
ObjectInputStream
提供了读取原始数据类型的方法。这些方法与 ObjectOutputStream
中的方法相对应。每种方法都从流中读取下一个原始值。
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("primitives.dat"))) { // Read primitives in same order they were written boolean bool = ois.readBoolean(); byte b = ois.readByte(); char c = ois.readChar(); double d = ois.readDouble(); float f = ois.readFloat(); int i = ois.readInt(); long l = ois.readLong(); short s = ois.readShort(); String str = ois.readUTF(); System.out.println("Read boolean: " + bool); System.out.println("Read byte: " + b); System.out.println("Read char: " + c); System.out.println("Read double: " + d); System.out.println("Read float: " + f); System.out.println("Read int: " + i); System.out.println("Read long: " + l); System.out.println("Read short: " + s); System.out.println("Read String: " + str); } catch (IOException e) { e.printStackTrace(); } } }
此示例从文件读取原始值。这些值必须以写入的完全相同的顺序读取。try-with-resources 确保正确关闭流。每种读取方法都对应于特定的原始类型。
使用 readObject 读取对象
readObject
方法从序列化数据重建对象。对象的类必须实现 Serializable
并且在 JVM 中可用。该方法可能会抛出 ClassNotFoundException
。
import java.io.Serializable; public class Person implements Serializable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } }
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) { // Read object and cast to Person Person person = (Person) ois.readObject(); System.out.println("Deserialized Person: " + person); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
此示例演示了对象反序列化。Person
类必须实现 Serializable
。readObject
方法返回一个 Object
,必须将其强制转换为正确的类型。必须处理 IOException
和 ClassNotFoundException
。
读取多个对象和数组
ObjectInputStream
可以从流中读取多个对象和数组。对象按照写入的顺序读取。可以使用 readObject
反序列化原始类型或对象的数组。
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objects.dat"))) { // Read multiple objects String message = (String) ois.readObject(); int[] numbers = (int[]) ois.readObject(); Person person = (Person) ois.readObject(); System.out.println("Message: " + message); System.out.print("Numbers: "); for (int num : numbers) { System.out.print(num + " "); } System.out.println("\nPerson: " + person); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
此示例从流中读取多个对象。这些对象必须以写入的相同顺序读取。该数组被强制转换为适当的类型。这里重用了前一个示例中的 Person
类。
使用 readUnshared 进行自定义反序列化
readUnshared
方法确保每次反序列化都返回一个唯一的对象。与 readObject
不同,它防止共享反序列化的对象。当必须保留对象身份时,这很有用。
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("shared.dat"))) { // Read with readObject (may return shared reference) Object obj1 = ois.readObject(); Object obj2 = ois.readObject(); // Read with readUnshared (always new instance) Object obj3 = ois.readUnshared(); Object obj4 = ois.readUnshared(); System.out.println("readObject same instance? " + (obj1 == obj2)); System.out.println("readUnshared same instance? " + (obj3 == obj4)); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
此示例比较了 readObject
和 readUnshared
。前者可能会为同一对象的多次读取返回共享引用。后者始终返回唯一实例。这会影响对象身份比较。
使用 serialVersionUID 处理版本控制
当类发展时,serialVersionUID
确保兼容性。它是序列化类的版本号。不匹配会导致 InvalidClassException
。显式 UID 提供版本控制。
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("versioned.dat"))) { VersionedObject obj = (VersionedObject) ois.readObject(); System.out.println("Deserialized versioned object: " + obj); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } } class VersionedObject implements Serializable { private static final long serialVersionUID = 1L; // Explicit version UID private String data; public VersionedObject(String data) { this.data = data; } @Override public String toString() { return "VersionedObject{data='" + data + "'}"; } }
此示例显示了一个具有显式 serialVersionUID
的类。当对类进行不兼容的更改时,应更新 UID。这可以防止旧的序列化实例反序列化期间的版本不匹配错误。
来源
在本文中,我们介绍了 Java ObjectInputStream 类的基本方法和特性。理解这些概念对于在 Java 应用程序中使用对象序列化至关重要。
作者
列出所有Java教程。