Java ObjectOutputStream Class
Last modified: April 16, 2025
The java.io.ObjectOutputStream
class writes primitive data types and
objects to an OutputStream. It is used for Java object serialization, converting
objects into a byte stream. The serialized objects can be reconstructed using
ObjectInputStream.
ObjectOutputStream
implements the ObjectOutput
and
ObjectStreamConstants
interfaces. It handles both primitive types
and object graphs. Only objects implementing Serializable
can be
written. The stream includes type information for proper deserialization.
ObjectOutputStream Class Overview
ObjectOutputStream
provides methods for writing objects and
primitives to a stream. It maintains references to previously written objects
to handle circular references. The class writes a stream header that must be
matched by 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(); }
The code above shows key methods provided by ObjectOutputStream
.
These methods allow writing objects and primitives to an output stream. The
class handles object serialization according to Java's serialization protocol.
Creating an ObjectOutputStream
ObjectOutputStream is created by wrapping it around another OutputStream. The constructor writes a stream header that must be present for deserialization. Always close the stream when done to ensure all data is written.
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(); } } }
This example demonstrates basic ObjectOutputStream creation. The FileOutputStream provides the underlying byte stream. The ObjectOutputStream constructor may throw IOException if it cannot write the stream header. Always close streams in a finally block or use try-with-resources.
Writing Primitive Types
ObjectOutputStream provides methods for writing all Java primitive types. These methods write the data in a platform-independent format. The data can be read back using corresponding methods in 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(); } } }
This example shows writing different primitive types to a file. The try-with-resources statement ensures proper stream closure. Each write method handles a specific primitive type. The data is written in a binary format that preserves type information.
Serializing Objects
The primary purpose of ObjectOutputStream is writing objects. The object's class must implement Serializable. The writeObject method handles the entire object graph, including referenced objects. Transient fields are not serialized.
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(); } } }
This example demonstrates object serialization. The Person class implements Serializable. The password field is marked transient and won't be saved. The writeObject method serializes the entire object. Deserialization would recreate the object with its field values.
Writing Arrays and Collections
ObjectOutputStream can serialize arrays and standard collections. All elements must be serializable. The stream preserves the structure of collections and arrays. Nested collections are handled recursively.
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(); } } }
This example shows serialization of an array and ArrayList. Both the array and collection implement Serializable. The stream preserves the exact structure and contents. During deserialization, the objects will be reconstructed with the same contents.
Custom Serialization with writeObject
Classes can define custom serialization by implementing writeObject. This method must be private and handle writing the object's state. It typically calls defaultWriteObject first, then writes additional data.
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(); } } }
This example demonstrates custom serialization. The Account class implements writeObject to mask the account number. defaultWriteObject handles normal field serialization. Custom data can be added after calling defaultWriteObject. A matching readObject method would be needed for deserialization.
Resetting the Stream
The reset method clears the object cache, allowing duplicate objects to be written as new objects. This is useful when sending multiple copies of the same object. Without reset, subsequent writes would reference the first instance.
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(); } } }
This example shows the effect of reset on object serialization. The first two writes of sharedString create one object plus a reference. After reset, the third write creates a new copy. This behavior is important for network protocols where each write should be independent.
Source
Java ObjectOutputStream Class Documentation
In this article, we've covered the essential methods and features of the Java ObjectOutputStream class. Understanding object serialization is crucial for persistence and network communication in Java applications.
Author
List all Java tutorials.