Java ObjectOutputStream Class
In Java, the ObjectOutputStream
class, part of the java.io
package, plays a critical role in serialization. It enables the process of writing (serializing) objects into an output stream, making it possible to store or transmit the objects in a format that can be restored (deserialized) later. The ObjectOutputStream
is the counterpart to ObjectInputStream
, which is used for deserializing (reading back) objects from streams.
Serialization in Java allows objects to be converted into a byte stream, which can then be written to a file or sent over a network. This is essential for object persistence or for sending complex data structures in distributed systems. ObjectOutputStream
is used to serialize objects, while ObjectInputStream
is used for deserialization.
In this post, we will delve into the ObjectOutputStream
class, explore its key methods, and show you practical examples of how to use it for writing objects to files and streams.
The ObjectOutputStream
class is a subclass of OutputStream
, and its primary function is to serialize objects to an output stream. Once serialized, the object can be written to a variety of destinations, such as a file, database, or network socket.
Serialization involves converting an object into a byte stream, which can then be saved or transmitted. The object must implement the Serializable
interface for this process to work. Non-serializable objects will cause an error when you attempt to serialize them.
The ObjectOutputStream
class provides several essential methods for serializing objects. Here are the most important ones:
void writeObject(Object obj)
:
Serializes the specified object and writes it to the output stream. If the object is not serializable, a java.io.NotSerializableException
will be thrown.
objectOutputStream.writeObject(someObject);
void write(byte[] b)
:
Writes an array of bytes to the stream, similar to how bytes are written in other streams.
void flush()
:
Flushes the stream, ensuring that any data buffered by the stream is written to the destination.
void close()
:
Closes the output stream and releases any system resources associated with it.
void writeObjectOverride(Object obj)
:
This method can be used for custom serialization logic in the class. It is part of the custom serialization process and can override the default serialization behavior.
void writeUnshared(Object obj)
:
This writes an object to the stream without attempting to check whether it has been written before in the current stream. It is useful in cases where multiple references to the same object need to be serialized independently.
This is the most common use case for ObjectOutputStream
—serializing an object to a file.
import java.io.*;
class Person implements Serializable {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class ObjectOutputStreamExample {
public static void main(String[] args) {
Person person = new Person("Alice", 30);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
oos.writeObject(person); // Serialize the person object
System.out.println("Person object serialized successfully.");
} catch (IOException e) {
System.out.println("An error occurred during serialization.");
e.printStackTrace();
}
}
}
Explanation:
Person
class implements the Serializable
interface, allowing its instances to be serialized.ObjectOutputStream
is used to write the person
object to a file named person.ser
.writeObject()
method is used to serialize the object and save it to the file.Output:
Person object serialized successfully.
You can use ObjectOutputStream
to serialize multiple objects to a stream.
import java.io.*;
class Person implements Serializable {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class SerializeMultipleObjects {
public static void main(String[] args) {
Person person1 = new Person("John", 25);
Person person2 = new Person("Mary", 28);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("people.ser"))) {
oos.writeObject(person1); // Serialize the first person object
oos.writeObject(person2); // Serialize the second person object
System.out.println("Two person objects serialized successfully.");
} catch (IOException e) {
System.out.println("An error occurred during serialization.");
e.printStackTrace();
}
}
}
Explanation:
Person
objects are created and serialized to the people.ser
file.writeObject()
.Output:
Two person objects serialized successfully.
You can implement custom serialization behavior by overriding the writeObject()
method in your class.
import java.io.*;
class Person implements Serializable {
String name;
transient int age; // transient fields are not serialized by default
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // Serialize default fields
oos.writeInt(age * 2); // Custom serialization logic: writing age * 2
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class CustomSerializationExample {
public static void main(String[] args) {
Person person = new Person("Alice", 30);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person_custom.ser"))) {
oos.writeObject(person); // Serialize the person object with custom logic
System.out.println("Person object with custom serialization serialized successfully.");
} catch (IOException e) {
System.out.println("An error occurred during serialization.");
e.printStackTrace();
}
}
}
Explanation:
Person
class has a transient
field age
, meaning it will not be serialized by default.writeObject()
method is overridden to customize the serialization of the age
field. Here, the age is serialized as age * 2
instead of its original value.Output:
Person object with custom serialization serialized successfully.
ObjectOutputStream
makes it easy to write serialized objects to files or network streams. This is particularly useful for storing objects in files or transmitting them between different components of a system.writeObject()
method to customize the way an object is serialized. This is useful for handling transient fields, special data formats, or complex objects.ObjectOutputStream
handles object references, ensuring that objects are written once even if they are referenced multiple times in the object graph.