Java ObjectOutputStream 类
最后修改时间:2025 年 4 月 16 日
java.io.ObjectOutputStream
类将基本数据类型和对象写入 OutputStream。 它用于 Java 对象序列化,将对象转换为字节流。 序列化的对象可以使用 ObjectInputStream 重新构造。
ObjectOutputStream
实现了 ObjectOutput
和 ObjectStreamConstants
接口。 它处理基本类型和对象图。 只有实现 Serializable
的对象才能被写入。 流包括用于正确反序列化的类型信息。
ObjectOutputStream 类概述
ObjectOutputStream
提供了将对象和基本类型写入流的方法。 它维护对先前写入对象的引用以处理循环引用。 该类写入一个流头,该流头必须与 ObjectInputStream 匹配。
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { public ObjectOutputStream(OutputStream out); public final void writeObject(Object obj); public void writeInt(int val); public void writeUTF(String str); public void defaultWriteObject(); public void reset(); public void close(); }
上面的代码展示了 ObjectOutputStream
提供的关键方法。 这些方法允许将对象和基本类型写入输出流。 该类根据 Java 的序列化协议处理对象序列化。
创建 ObjectOutputStream
ObjectOutputStream 通过将其包装在另一个 OutputStream 中创建。 构造函数写入一个流头,该流头必须存在于反序列化中。 完成后,始终关闭流以确保写入所有数据。
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Main { public static void main(String[] args) { try { // Create a FileOutputStream FileOutputStream fileOut = new FileOutputStream("object.dat"); // Wrap it in ObjectOutputStream ObjectOutputStream objectOut = new ObjectOutputStream(fileOut); System.out.println("ObjectOutputStream created successfully"); // Always close the stream objectOut.close(); } catch (IOException e) { e.printStackTrace(); } } }
此示例演示了基本的 ObjectOutputStream 创建。 FileOutputStream 提供了底层的字节流。 ObjectOutputStream 构造函数可能会抛出 IOException,如果它无法写入流头。 始终在 finally 块中关闭流或使用 try-with-resources。
写入基本类型
ObjectOutputStream 提供了用于写入所有 Java 基本类型的方法。 这些方法以与平台无关的格式写入数据。 可以使用 ObjectInputStream 中的相应方法将数据读回。
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Main { public static void main(String[] args) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("primitives.dat"))) { // Write various primitive types oos.writeBoolean(true); oos.writeByte((byte) 65); oos.writeChar('A'); oos.writeDouble(3.14159); oos.writeFloat(2.718f); oos.writeInt(42); oos.writeLong(123456789L); oos.writeShort((short) 1000); System.out.println("Primitives written successfully"); } catch (IOException e) { e.printStackTrace(); } } }
此示例展示了将不同的基本类型写入文件。 try-with-resources 语句确保了正确的流关闭。 每个写入方法处理一个特定的基本类型。 数据以保留类型信息的二进制格式写入。
序列化对象
ObjectOutputStream 的主要目的是写入对象。 对象的类必须实现 Serializable。 writeObject 方法处理整个对象图,包括引用的对象。 transient 字段不会被序列化。
import java.io.Serializable; public class Person implements Serializable { private String name; private int age; private transient String password; // Won't be serialized public Person(String name, int age, String password) { this.name = name; this.age = age; this.password = password; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Main { public static void main(String[] args) { Person person = new Person("Alice", 30, "secret123"); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) { oos.writeObject(person); System.out.println("Person object serialized: " + person); } catch (IOException e) { e.printStackTrace(); } } }
此示例演示了对象序列化。 Person 类实现了 Serializable。 密码字段被标记为 transient,不会被保存。 writeObject 方法序列化整个对象。 反序列化将使用其字段值重新创建对象。
写入数组和集合
ObjectOutputStream 可以序列化数组和标准集合。 所有元素都必须是可序列化的。 流保留了集合和数组的结构。 嵌套集合被递归处理。
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { // Create sample data int[] numbers = {1, 2, 3, 4, 5}; List<String> names = new ArrayList<>( Arrays.asList("Alice", "Bob", "Charlie")); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("collections.dat"))) { // Write array oos.writeObject(numbers); // Write collection oos.writeObject(names); System.out.println("Array and collection serialized"); } catch (IOException e) { e.printStackTrace(); } } }
此示例展示了数组和 ArrayList 的序列化。 数组和集合都实现了 Serializable。 流保留了确切的结构和内容。 在反序列化期间,对象将被重建,并具有相同的内容。
使用 writeObject 自定义序列化
类可以通过实现 writeObject 来定义自定义序列化。 此方法必须是私有的,并处理写入对象的状态。 它通常首先调用 defaultWriteObject,然后写入其他数据。
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class Account implements Serializable { private String accountNumber; private double balance; private Date lastTransaction; public Account(String accountNumber, double balance) { this.accountNumber = accountNumber; this.balance = balance; this.lastTransaction = new Date(); } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); // Serialize normal fields out.writeUTF(accountNumber.substring(0, 2) + "XXXXXX"); // Mask number } // readObject would be needed for deserialization @Override public String toString() { return "Account [number=" + accountNumber + ", balance=" + balance + "]"; } }
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Main { public static void main(String[] args) { Account account = new Account("1234567890", 1000.0); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("account.dat"))) { oos.writeObject(account); System.out.println("Account serialized with custom writeObject"); } catch (IOException e) { e.printStackTrace(); } } }
此示例演示了自定义序列化。 Account 类实现了 writeObject 以掩盖帐号。 defaultWriteObject 处理正常的字段序列化。 可以在调用 defaultWriteObject 之后添加自定义数据。 反序列化需要一个匹配的 readObject 方法。
重置流
reset 方法清除对象缓存,允许将重复的对象写入为新对象。 这在发送相同对象的多个副本时很有用。 如果没有 reset,后续的写入将引用第一个实例。
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Main { public static void main(String[] args) { String sharedString = "Shared String"; try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("reset.dat"))) { // Write first instance oos.writeObject(sharedString); // Write second instance (will be treated as reference) oos.writeObject(sharedString); // Reset the stream oos.reset(); // Write third instance (new copy) oos.writeObject(sharedString); System.out.println("Objects written with reset"); } catch (IOException e) { e.printStackTrace(); } } }
此示例展示了 reset 对对象序列化的影响。 前两次对 sharedString 的写入创建一个对象加上一个引用。 在 reset 之后,第三次写入创建一个新的副本。 此行为对于每个写入都应该独立的网络协议非常重要。
来源
在本文中,我们介绍了 Java ObjectOutputStream 类的基本方法和特性。 了解对象序列化对于 Java 应用程序中的持久性和网络通信至关重要。
作者
列出所有Java教程。