Java ObjectInputStream Class
Last modified: April 16, 2025
The java.io.ObjectInputStream
class deserializes primitive data and
objects previously written using ObjectOutputStream
. It reconstructs
objects from their serialized form. The class implements ObjectInput
and ObjectStreamConstants
interfaces.
ObjectInputStream
reads serialized data from an underlying input
stream. It handles object graphs, cyclic references, and class versioning. The
class provides methods to read primitives, objects, and arrays from the stream.
ObjectInputStream Class Overview
ObjectInputStream
extends InputStream
and implements
object deserialization. Key methods include reading primitives, objects, and
custom deserialization via readObject
. The class maintains state
for handling object references.
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; }
The code above shows key methods provided by ObjectInputStream
.
These methods allow reading primitive types and objects from a serialized stream.
The class handles object reconstruction and reference resolution automatically.
Creating an ObjectInputStream
ObjectInputStream is created by wrapping it around another InputStream
.
The constructor may throw IOException
if stream header is invalid.
Always close the stream when done to release resources.
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()); } } }
This example demonstrates basic creation of an ObjectInputStream
.
The stream is wrapped around a FileInputStream
reading from a file.
Error handling is important as the constructor may throw IOException
.
Reading Primitive Types
ObjectInputStream
provides methods to read primitive data types. These
methods correspond to those in ObjectOutputStream
. Each method reads
the next primitive value from the stream.
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(); } } }
This example reads primitive values from a file. The values must be read in the exact same order they were written. The try-with-resources ensures proper stream closure. Each read method corresponds to a specific primitive type.
Reading Objects with readObject
The readObject
method reconstructs objects from serialized data.
The object's class must implement Serializable
and be available in
the JVM. The method may throw 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(); } } }
This example demonstrates object deserialization. The Person
class
must implement Serializable
. The readObject
method
returns an Object
that must be cast to the correct type. Both
IOException
and ClassNotFoundException
must be handled.
Reading Multiple Objects and Arrays
ObjectInputStream
can read multiple objects and arrays from a stream.
The objects are read in the order they were written. Arrays of primitives or
objects can be deserialized using 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(); } } }
This example reads multiple objects from a stream. The objects must be read in the
same order they were written. The array is cast to the appropriate type. The
Person
class from the previous example is reused here.
Custom Deserialization with readUnshared
The readUnshared
method ensures each deserialization returns a
unique object. Unlike readObject
, it prevents sharing of
deserialized objects. This is useful when object identity must be preserved.
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(); } } }
This example compares readObject
and readUnshared
.
The former may return shared references for multiple reads of same object. The
latter always returns unique instances. This affects object identity comparison.
Handling Versioning with serialVersionUID
When classes evolve, serialVersionUID
ensures compatibility. It's a
version number for serialized classes. Mismatches cause
InvalidClassException
. Explicit UID provides version control.
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 + "'}"; } }
This example shows a class with explicit serialVersionUID
. The UID
should be updated when making incompatible changes to the class. This prevents
version mismatch errors during deserialization of older serialized instances.
Source
Java ObjectInputStream Class Documentation
In this article, we've covered the essential methods and features of the Java ObjectInputStream class. Understanding these concepts is crucial for working with object serialization in Java applications.
Author
List all Java tutorials.