Friday, 15 March 2013

Object Stream in Java

Background

Just to recall we have are going through I/O streams in Java. We have already seen byte stream, character stream and use of scanner class. Lets see the final topic on I/O streams in Java i.e Object stream.

Object streams

       Object streams are used for I/O of objects. For objects of classes to support this I/O they must implement a special interface called Serializable Interfaces are not explained yet so do not bother what that is as of now but just from the programming perspective it is as simple as saying 

class ObjectStreamDemo implements Serializable
{
      //member variables and functions 
} 

 Serializable in itself is a topic worth a post which we can cover in next tutorial but as of now i will demonstrate how can we read and write objects through object streams.

Java code 

      We will create a class, create it's object, store it in a file and retrieve it.Sounds simple enough? It actually is!

Let us create a simple class ObjectStreamDemo first.It must implement Serializable in order to use it's objects in Object stream.

package streamsDemo;
import java.io.Serializable;

public class ObjectStreamDemo implements Serializable {

private static final long serialVersionUID = 1L;    
private String greetings;

    public String getGreetings() {
        return greetings;
    }

    public void setGreetings(String greetings) {
        this.greetings = greetings;
    }

}
     So now we have a class which implements Serializable. We have an instance variable called greetings and we have defined it's getter and setter methods.Note you have to import java.io.Serializable.Wondering what serialVersionUID  is? We will come to that in some time. Now lets move on to implementation of Object streams.

package streamsDemo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class ObjectStreamImplementation {

    public static void main(String args[]) {
        ObjectStreamDemo obj = new ObjectStreamDemo();
        obj.setGreetings("Hello World!");
        ObjectInputStream ois = null;
        ObjectOutput oos = null;

        try {
            try {
                oos = new ObjectOutputStream(new FileOutputStream(new File(
                        "testFile.txt")));
                ois = new ObjectInputStream(new FileInputStream(new File(
                        "testFile.txt")));
                oos.writeObject(obj);
                ObjectStreamDemo newObj = (ObjectStreamDemo) ois.readObject();
                System.out.println("greetings : " + newObj.getGreetings());
            } finally {
                if (ois != null) {
                    ois.close();
                }
                if (oos != null) {
                    oos.close();
                }

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

}

Output

Standard Output in Eclipse


Before we move on to understanding the code just go through the try-catch block. I had explained it while explaining code in character streams. You may want to go through it once. Also note why have we initialized ois and oos to null .Answer is because they are local variables and compiler will complaint if we use local variables without initializing. Refer this post to check revise the differences between local variables and instance variables.

Understanding the code

        In the main function we create an object of ObjectStreamDemo class called obj. Then we set it's instance variable greetings to "Hello World!". Then we declare references  to objects of ObjectInputStream and ObjectOutputStream. Note these are just reference and not objects.What i mean by that is no memory is allocated on heap. These are just pointers which we know will point to objects of ObjectInputStream and ObjectOutputStream.
      Next we actually create object of ObjectInputStream and  ObjectOutputStream. Expression looks familiar. Yes! it does. ObjectInputStream and ObjectOutputStream are just wrappers around FileInputStream and FileOutputStream which are nothing but byte I/O streams for file operations.Then we write the object we created obj to the file.Finally we read the object objNew from file and print it's instance variable greetings on the standard output. Output is as expected "Hello World!"

Note : we have to type cast to ObjectStreamDemo as .readObject() will return an Object.

What is this serialVersionUID we defined in

ObjectStreamDemo class and what is it's use?

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members.

If you using an IDE like Eclipse or Netbeans you will automatically get warning to  put a  serialVersionUID. IDE can also put a default value if you instruct so.

Related Links

    

No comments:

Post a Comment

t> UA-39527780-1 back to top