Object I/O
Tags: java, programming, learning, beginners
Published: 2024-07-01 13:28:55

**ObjectInputStream**/**ObjectOutputStream** classes can be used to read/write serializable objects. **DataInputStream**/**DataOutputStream** enables you to perform I/O for primitive-type values and strings. **ObjectInputStream**/**ObjectOutputStream** enables you to perform I/O for objects in addition to primitive-type values and strings. Since **ObjectInputStream**/**ObjectOutputStream** contains all the functions of **DataInputStream**/**DataOutputStream**, you can replace **DataInputStream**/**DataOutputStream** completely with **ObjectInputStream**/**ObjectOutputStream**.

**ObjectInputStream** extends **InputStream** and implements **ObjectInput** and **ObjectStreamConstants**, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3xmedb7aezh7vj6b8fcw.png)

**ObjectInput** is a subinterface of **DataInput**. **ObjectStreamConstants** contains the constants to support **ObjectInputStream**/**ObjectOutputStream**. **ObjectOutputStream** extends **OutputStream** and implements **ObjectOutput** and **ObjectStreamConstants**, as shown in Figure below. **ObjectOutput** is a subinterface of **DataOutput**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2akvntvj4loil392yjc6.png)

You can wrap an **ObjectInputStream**/**ObjectOutputStream** on any **InputStream**/**OutputStream** using the following constructors:

`// Create an ObjectInputStream
public ObjectInputStream(InputStream in)`

`// Create an ObjectOutputStream
public ObjectOutputStream(OutputStream out)`

The code below writes student names, scores, and the current date to a file named object.dat.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6a0ir09zwisany00z867.png)

An **ObjectOutputStream** is created to write data into the file **object.dat** in lines 8. A string, a double value, and an object are written to the file in lines 11–13. To improve performance, you may add a buffer in the stream using the following statement to replace lines 8:

`ObjectOutputStream output = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream("object.dat")));`

Multiple objects or primitives can be written to the stream. The objects must be read back from the corresponding **ObjectInputStream** with the same types and in the same order as they were written. Java’s safe casting should be used to get the desired type. The code below reads data from **object.dat**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jh7ppdaviumpv3y56alw.png)

The **readObject()** method may throw **java.lang.ClassNotFoundException**, because when the JVM restores an object, it first loads the class for the object if the class has not been loaded. Since **ClassNotFoundException** is a checked exception, the **main** method declares to throw it in line 6. An **ObjectInputStream** is created to read input from **object.dat** in lines 8. You have to read the data from the file in the same order and format as they were written to the file. A string, a double value, and an object are read in lines 11–13. Since **readObject()** returns an **Object**, it is cast into **Date** and assigned to a **Date** variable in line 13.

##  The Serializable Interface

Not every object can be written to an output stream. Objects that can be so written are said to be _serializable_. A serializable object is an instance of the **java.io.Serializable** interface, so the object’s class must implement **Serializable**.

The **Serializable** interface is a marker interface. Since it has no methods, you don’t need to add additional code in your class that implements **Serializable**. Implementing this interface enables the Java serialization mechanism to automate the process of storing objects and arrays.

To appreciate this automation feature, consider what you otherwise need to do in order to store an object. Suppose you wish to store an **ArrayList** object. To do this you need to store all the elements in the list. Each element is an object that may contain other objects. As you can see, this would be a very tedious process. Fortunately, you don’t have to go through it manually. Java provides a built-in mechanism to automate the process of writing objects. This process is referred as _object serialization_, which is implemented in **ObjectOutputStream**. In contrast, the process of reading objects is referred as _object deserialization_, which is implemented in **ObjectInputStream**.

Many classes in the Java API implement **Serializable**. All the wrapper classes for primitive type values, **java.math.BigInteger**, **java.math.BigDecimal**, **java.lang.String**, **java.lang.StringBuilder**, **java.lang.StringBuffer**, **java.util.Date**, and **java.util.ArrayList** implement **java.io.Serializable**. Attempting to store an object that does not support the **Serializable** interface would cause a **NotSerializableException**.

When a serializable object is stored, the class of the object is encoded; this includes the class name and the signature of the class, the values of the object’s instance variables, and the closure of any other objects referenced by the object. The values of the object’s static variables are not stored.

**Nonserializable fields**

If an object is an instance of **Serializable** but contains nonserializable instance data fields, can it be serialized? The answer is no. To enable the object to be serialized, mark these data fields with the **transient** keyword to tell the JVM to ignore them when writing the object to an object stream. Consider the following class:

`public class C implements java.io.Serializable {
private int v1;
private static double v2;
private transient A v3 = new A();
}
class A { } // A is not serializable`

When an object of the **C** class is serialized, only variable **v1** is serialized. Variable **v2** is not serialized because it is a static variable, and variable **v3** is not serialized because it is marked **transient**. If **v3** were not marked **transient**, a **java.io.NotSerializableException** would occur.

**Duplicate objects**

If an object is written to an object stream more than once, will it be stored in multiple copies? No, it will not. When an object is written for the first time, a serial number is created for it. The JVM writes the complete contents of the object along with the serial number into the object stream. After the first time, only the serial number is stored if the same object is written again. When the objects are read back, their references are the same since only one object is actually created in the memory.

## Serializing Arrays

An array is serializable if all its elements are serializable. An entire array can be saved into a file using **writeObject** and later can be restored using **readObject**. The code below stores an array of five **int** values and an array of three strings and reads them back to display on the console.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afs1gadwcahttar6beqx.png)

Lines 14 and 15 write two arrays into file **array.dat**. Lines 21 and 22 read two arrays back in the same order they were written. Since **readObject()** returns **Object**, casting is used to cast the objects into **int[]** and **String[]**.