I/O Object serialization

When you create an object, it exists for as long as you need it, but under no circumstances does it exist when the program terminates.
there are situations in which it would be incredibly useful if an object could exist and hold its information even while the program wasn’t running.
the next time you started the program, the object would be there and it would have the same information it had the previous time the program was running.
Of course, you can get a similar effect by writing the information to a file or to a database, but in the spirit of making everything an object, it would be quite convenient to declare an object to be "persistent," and have all the details taken care of for you.

Java’s object serialization allows you to take any object that implements the Serializable interface and turn it into a sequence of bytes that can later be fully restored to regenerate the original object.
This is even true across a network, which means that the serialization mechanism automatically compensates for differences in operating systems. That is, you can create an object on a Windows machine, serialize it, and send it across the network to a Unix machine, where it will be correctly reconstructed. You don’t have to worry about the data representations on the different machines, the byte ordering, or any other details.

Object serialization was added to the language to support two major features.
  • Java’s Remote Method Invocation (RMI) allows objects that live on other machines to behave as if they live on your machine.
    When messages are sent to remote objects, object serialization is necessary to transport the arguments and return values.
  • Object serialization is also necessary for JavaBeans.When a Bean is used, its state information is generally configured at design time. This state information must be stored and later recovered when the program is started; object serialization performs this task.

Serializing an object is quite simple as long as the object implements the Serializable interface.

 

When serialization was added to the language, many standard library classes were changed to make them serializable, including all of the wrappers for the primitive types, all of the container classes, and many others. Even Class objects can be serialized.

 


To serialize an object, you create some sort of OutputStream object and then wrap it inside an ObjectOutputStream object. At this point you need only call writeObject( ), and your object is serialized and sent to the OutputStream (object serialization is byte-oriented, and thus uses the InputStream and OutputStream hierarchies). To reverse the process, you wrap an InputStream inside an ObjectlnputStream and call readObject( ). What comes back is, as usual, a reference to an upcast Object, so you must downcast to set things straight.


Externalizable
The Externalizable interface extends the Serializable interface and adds two methods, writeExternal( ) and readExternal( ), that are automatically called for your object during serialization and deserialization so that you can perform your special operations.
This is different from recovering a Serializable object, in which the object is constructed entirely from its stored bits, with no constructor calls.
the fact that: all the default construction always takes place—to produce the correct behavior in your Externalizable objects.

Here’s an example that shows what you must do to fully store and retrieve an Externalizable object:
//: io/Blip3.java
// Reconstructing an externalizable object.
import java.io.*;
import static net.mindview.util.Print.*;

public
 class Blip3 implements Externalizable {
    private int i;
    private String s; // No initialization
   
    public Blip3() {
        print("Blip3 Constructor");
        // s, i not initialized
    }

    public Blip3(String x, int a) {
        print("Blip3(String x, int a)");
        = x;
        = a;
        // s & i initialized only in non-default constructor.
    }

    public String toString() { return s + i; }

    public void writeExternal(ObjectOutput out) throws IOException {
        print("Blip3.writeExternal");
        // You must do this:
        out.writeObject(s);
        out.writeInt(i);
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        print("Blip3.readExternal");
        // You must do this:
        = (String)in.readObject();
        = in.readInt();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        print("Constructing objects:");
        Blip3 b3 = new Blip3("A String "47);
        print(b3);
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Blip3.out"));
        print("Saving object:");
        o.writeObject(b3);
        o.close();
        // Now get it back:
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("Blip3.out"));
        print("Recovering b3:");
        b3 = (Blip3)in.readObject();
        print(b3);
    }
}
If you comment out the two lines of code following the phrases "You must do this:" and run the program, you’ll see that when the object is recovered, s is null and i is zero.
If you are inheriting from an Externalizable object, you’ll typically call the base-class versions of writeExternal( ) and readExternal( ) to provide proper storage and retrieval of the base-class components.

One way to prevent sensitive parts of your object from being serialized is to implement your class as Externalizable, as shown previously. Then nothing is automatically serialized, and you can explicitly serialize only the necessary parts inside writeExternal( ).


transient
If you’re working with a Serializable object, however, all serialization happens automatically. To control this, you can turn off serialization on a field-by-field basis using the transient keyword, which says, "Don’t bother saving or restoring this—I’ll take care of it."

For example, consider a Logon object that keeps information about a particular login session. Suppose that, once you verify the login, you want to store the data, but without the password. The easiest way to do this is by implementing Serializable and marking the password field as transient.
Here’s what it looks like:
//: io/Logon.java
// Demonstrates the "transient" keyword.
import java.util.concurrent.*;
import java.io.*;
import java.util.*;
import static net.mindview.util.Print.*;

public class Logon implements Serializable {
    
private Date date = new Date();
    
private String username;
    
private transient String password;

    
public Logon(String name, String pwd) {
        username 
= name;
        password 
= pwd;
    }

    
public String toString() {
        
return "logon info: \n username: " + username + "\n date: " + date
                
+ "\n password: " + password;
    }

    
public static void main(String[] args) throws Exception {
        Logon a 
= new Logon("Hulk""myLittlePony");
        print(
"logon a = " + a);
        ObjectOutputStream o 
= new ObjectOutputStream(new FileOutputStream(
                
"Logon.out"));
        o.writeObject(a);
        o.close();
        TimeUnit.SECONDS.sleep(
1); // Delay
        
// Now get them back:
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                
"Logon.out"));
        print(
"Recovering object at " + new Date());
        a 
= (Logon) in.readObject();
        print(
"logon a = " + a);
    }
/*
 * Output: (Sample) 
 * logon a = logon info: 
 *         username: Hulk 
 *         date: Sat Nov 19 15:03:26 MST 2005 
 *         password: myLittlePony 
 * Recovering object at Sat Nov 19 15:03:28 MST 2005 
 * logon a = logon info: 
 *         username: Hulk 
 *         date: Sat Nov 1915:03:26 MST 2005 
 *         password: null
 
*/// :~


Anything defined in an interface is automatically public, so if writeObject( ) and readObject( ) must be private, then they can’t be part of an interface. Since you must follow the signatures exactly, the effect is the same as if you’re implementing an interface.
It would appear that when you call ObjectOutputStream.writeObject( ), the Serializable object that you pass it to is interrogated (using reflection, no doubt) to see if it implements its own writeObject( ). If so, the normal serialization process is skipped and the custom writeObject( ) is called. The same situation exists for readObject( ).


It’s quite appealing to use serialization technology to store some of the state of your program so that you can easily restore the program to the current state later.

But before you can do this, some questions must be answered. What happens if you serialize two objects that both have a reference to a third object? When you restore those two objects from their serialized state, do you get only one occurrence of the third object? What if you serialize your two objects to separate files and deserialize them in different parts of your code?

//: io/MyWorld.java
import java.io.*;
import java.util.*;
import static net.mindview.util.Print.*;

class House implements Serializable {
}

class Animal implements Serializable {
    
private String name;
    
private House preferredHouse;

    Animal(String nm, House h) {
        name 
= nm;
        preferredHouse 
= h;
    }

    
public String toString() {
        
return name + "[" + super.toString() + "], " + preferredHouse + "\n";
    }
}

public class MyWorld {
    
public static void main(String[] args) throws IOException,
            ClassNotFoundException {
        House house 
= new House();
        List
<Animal> animals = new ArrayList<Animal>();
        animals.add(
new Animal("Bosco the dog", house));
        animals.add(
new Animal("Ralph the hamster", house));
        animals.add(
new Animal("Molly the cat", house));
        print(
"animals: " + animals);
        ByteArrayOutputStream buf1 
= new ByteArrayOutputStream();
        ObjectOutputStream o1 
= new ObjectOutputStream(buf1);
        o1.writeObject(animals);
        o1.writeObject(animals); 
// Write a 2nd set
        
// Write to a different stream:
        ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
        ObjectOutputStream o2 
= new ObjectOutputStream(buf2);
        o2.writeObject(animals);
        
// Now get them back:
        ObjectInputStream in1 = new ObjectInputStream(new ByteArrayInputStream(
                buf1.toByteArray()));
        ObjectInputStream in2 
= new ObjectInputStream(new ByteArrayInputStream(
                buf2.toByteArray()));
        List animals1 
= (List) in1.readObject(), animals2 = (List) in1
                .readObject(), animals3 
= (List) in2.readObject();
        print(
"animals1: " + animals1);
        print(
"animals2: " + animals2);
        print(
"animals3: " + animals3);
    }
}
/* Output: (Sample)
animals: [Bosco the dog[Animal@addbf1], House@42e816
, Ralph the hamster[Animal@9304b1], House@42e816
, Molly the cat[Animal@190d11], House@42e816
]
animals1: [Bosco the dog[Animal@de6f34], House@156ee8e
, Ralph the hamster[Animal@47b480], House@156ee8e
, Molly the cat[Animal@19b49e6], House@156ee8e
]
animals2: [Bosco the dog[Animal@de6f34], House@156ee8e
, Ralph the hamster[Animal@47b480], House@156ee8e
, Molly the cat[Animal@19b49e6], House@156ee8e
]
animals3: [Bosco the dog[Animal@10d448], House@e0e1c6
, Ralph the hamster[Animal@6ca1c], House@e0e1c6
, Molly the cat[Animal@1bf216a], House@e0e1c6
]
*///:~
Animal objects contain fields of type House. In main( ), a List of these Animals is created and it is serialized twice to one stream and then again to a separate stream. When these are deserialized and printed, you see the output shown for one run (the objects will be in different memory locations each run).

One thing that’s interesting here is that it’s possible to use object serialization to and from a byte array as a way of doing a "deep copy" of any object that’s Serializable. (A deep copy means that you’re duplicating the entire web of objects, rather than just the basic object and its references.) Object copying is covered in depth in the online supplements for this book.












posted on 2012-11-08 10:09 盐城小土包 阅读(147) 评论(0)  编辑  收藏 所属分类: J2EE


只有注册用户登录后才能发表评论。


网站导航:
 
<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿

随笔档案(14)

文章分类(18)

文章档案(18)

搜索

最新评论

阅读排行榜

评论排行榜