Flatten your objects

We all know Java allows us to create reusable objects in memory. However, all of those objects exist only as long as the virtual machine remains running. It would be nice if the objects we create could exist beyond the lifetime of the virtual machine, wouldn't it? Well, with object serialization, you can flatten your objects and reuse them in powerful ways.

Object serialization is the process of saving an object's state to a sequence of bytes, as well as the process of rebuilding those bytes into a live object at some future time. The Java Serialization API provides a standard mechanism for Java developers to handle object serialization. The API is small and easy to use, provided the classes and methods are understood.

Throughout this article, we'll examine how to persist your Java objects, starting with the basics and proceeding to the more advanced concepts. We'll learn three different ways to perform serialization -- using the default protocol, customizing the default protocol, and creating our own protocol -- and we'll investigate concerns that arise with any persistence scheme such as object caching, version control, and performance issues.

By the conclusion of this article, you should have a solid comprehension of that powerful yet sometimes poorly understood Java API.

First things first: The default mechanism

Let's start with the basics. To persist an object in Java, we must have a persistent object. An object is marked serializable by implementing the java.io.Serializable interface, which signifies to the underlying API that the object can be flattened into bytes and subsequently inflated in the future.

Let's look at a persistent class we'll use to demonstrate the serialization mechanism:

10 import java.io.Serializable;
20 import java.util.Date;
30 import java.util.Calendar;
40  public class PersistentTime implements Serializable

50  {
60     private Date time;
70     
80     public PersistentTime()
90     {
100      time = Calendar.getInstance().getTime();
110    }
120
130    public Date getTime()
140    {
150      return time;
160    }
170  }


As you can see, the only thing we had to do differently from creating a normal class is implement the java.io.Serializable interface on line 40. The completely empty Serializable is only a marker interface -- it simply allows the serialization mechanism to verify that the class is able to be persisted. Thus, we turn to the first rule of serialization:

Rule #1: The object to be persisted must implement the Serializable interface or inherit that implementation from its object hierarchy.

The next step is to actually persist the object. That is done with the java.io.ObjectOutputStream class. That class is a filter stream -- it is wrapped around a lower-level byte stream (called a node stream ) to handle the serialization protocol for us. Node streams can be used to write to file systems or even across sockets. That means we could easily transfer a flattened object across a network wire and have it be rebuilt on the other side!

Take a look at the code used to save the PersistentTime object:

10  import java.io.ObjectOutputStream;
20  import java.io.FileOutputStream;
30  import java.io.IOException;
40  public class FlattenTime
50  {
60    public static void main(String [] args)
70    {
80      String filename = "time.ser";
90      if(args.length > 0)
100     {
110       filename = args[0];
120     }          
130     PersistentTime time = new PersistentTime();
140     FileOutputStream fos = null;
150     ObjectOutputStream out = null;
160     try
170     {
180       fos = new FileOutputStream(filename);
190       out = new ObjectOutputStream(fos);
200       out.writeObject(time);
210       out.close();
220     }
230     catch(IOException ex)
240     {
250       ex.printStackTrace();
260     }
270   }
280 }


The real work happens on line 200 when we call the ObjectOutputStream.writeObject() method, which kicks off the serialization mechanism and the object is flattened (in that case to a file).

To restore the file, we can employ the following code:

10  import java.io.ObjectInputStream;
20  import java.io.FileInputStream;
30  import java.io.IOException;
40  import java.util.Calendar;
50  public class InflateTime
60  {
70    public static void main(String [] args)
80    {
90      String filename = "time.ser";     
100     if(args.length > 0)
110     {
120       filename = args[0];
130     }
140   PersistentTime time = null;
150   FileInputStream fis = null;
160   ObjectInputStream in = null;
170   try
180   {
190     fis = new FileInputStream(filename);
200     in = new ObjectInputStream(fis);
210     time = (PersistentTime)in.readObject();
220     in.close();
230   }
240   catch(IOException ex)
250   {
260     ex.printStackTrace();
270   }
280   catch(ClassNotFoundException ex)
290   {
300     ex.printStackTrace();
310   }
320   // print out restored time
330   System.out.println("Flattened time: " + time.getTime());
340   System.out.println();
350      // print out the current time
360   System.out.println("Current time: " + Calendar.getInstance().getTime());
370 }
380}


In the code above, the object's restoration occurs on line 210 with the ObjectInputStream.readObject() method call. The method call reads in the raw bytes that we previously persisted and creates a live object that is an exact replica of the original. Because readObject() can read any serializable object, a cast to the correct type is required. With that in mind, the class file must be accessible from the system in which the restoration occurs. In other words, the object's class file and methods are not saved; only the object's state is saved.

Later, on line 360, we simply call the getTime() method to retrieve the time that the original object flattened. The flatten time is compared to the current time to demonstrate that the mechanism indeed worked as expected.

你可能感兴趣的:(java,Scheme,360,performance)