In-depth understanding of Java Object Serialization (reproduced)

Source: Internet
Author: User
Tags object serialization serialization

Original address: http://developer.51cto.com/art/201202/317181.htm

1. What is the serialization of Java objects

The Java platform allows us to create reusable Java objects in memory, but in general, these objects can exist only when the JVM is running, that is, they will not have a longer life cycle than the JVM. In a real-world application, however, it is possible to require that the specified object be saved (persisted) after the JVM has stopped running, and that the saved object will be re-read in the future. The serialization of Java objects can help us implement this functionality.

Using Java object serialization, when you save an object, it saves its state as a set of bytes, and in the future, these bytes are assembled into objects. It is important to note that object serialization holds the "state" of the object, which is its member variable. It is to be concluded that object serialization does not focus on static variables in the class.

In addition to using object serialization when persisting objects, object serialization is used when RMI (remote method calls) is used, or when objects are passed through the network. The Java Serialization API provides a standard mechanism for handling object serialization, which is easy to use and will be covered in subsequent chapters of this article.

2. Simple example

In Java, as long as a class implements the Java.io.Serializable interface, it can be serialized. A serializable class person will be created here, and all the examples in this article will revolve around that class or its modified version.

The gender class, which is an enumeration type that represents gender:

public enum Gender {      MALE, FEMALE  

If you are familiar with Java enumeration types, you should know that each enum type inherits the class Java.lang.Enum by default, and that the class implements the Serializable interface, so the enumeration type object can be serialized by default.

The person class implements the Serializable interface, which contains three fields: name,string type; age,integer type; Gender,gender type. In addition, the ToString () method of the class is overridden to facilitate printing of content in a person instance.

public class Person implements Serializable {private String name = NULL;       Private Integer age = null;       Private Gender Gender = null;      Public person () {System.out.println ("None-arg constructor");          The public person (String name, Integer age, Gender Gender) {System.out.println ("Arg constructor");          THIS.name = name;          This.age = age;      This.gender = gender;      } public String GetName () {return name;      } public void SetName (String name) {this.name = name;      } public Integer Getage () {return age;      public void Setage (Integer age) {this.age = age;      } public Gender Getgender () {return Gender;      } public void Setgender (Gender Gender) {this.gender = Gender;      } @Override Public String toString () {return ' [' + name + ', ' + Age + ', ' + gender + '];  }  }

Simpleserial is a simple serializer that saves a person object to a file person.out, and then reads the stored person object from the file and prints the object.

public class Simpleserial {public       static void Main (string[] args) throws Exception {          file File = new file ("person . Out ");           ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream (file));          person person = new Person ("John", 101, Gender.male);          Oout.writeobject (person);          Oout.close ();           ObjectInputStream oin = new ObjectInputStream (new FileInputStream (file));          Object Newperson = Oin.readobject (); No cast to Person type          oin.close ();          System.out.println (Newperson);      }  

The result of the above program output is:

Arg constructor  

It is important to note that when you re-read the saved person object, there is no constructor that calls the person, and it looks like you are restoring the person object directly using bytes.

When the person object is saved to the Person.out file, we can read the file elsewhere to restore the object, but you must ensure that the classpath of the reader contains Person.class ( Even if the person class is not displayed when reading the person object, as in the example above, ClassNotFoundException will be thrown.

3. The role of Serializable

Why does a class implement the Serializable interface and it can be serialized? In the example in the previous section, using ObjectOutputStream to persist an object, there is the following code in the class:

private void WriteObject0 (Object obj, Boolean unshared) throws IOException {        ...    if (obj instanceof String) {          writestring (string) obj, unshared),      } else if (Cl.isarray ()) {          Writearray (obj, DESC, unshared);      } else if (obj instanceof Enum) {          writeenum ((Enum) obj, desc, unshared);      } else if (obj instanceof Serializable) {
   writeordinaryobject (obj, desc, unshared);      } else {          if (extendeddebuginfo) {              throw new Notserializableexception (Cl.getname () + "\ n"                     + Debuginfostack.tostring ());          } else {              throw new Notserializableexception (Cl.getname ());          }      }      ...  

From the code above, if the type of the object being written is a string, or an array, or an enum, or serializable, then the object can be serialized, or notserializableexception will be thrown.

4. Default serialization mechanism

If you just let a class implement the Serializable interface without any other processing, you would use the default serialization mechanism. Using the default mechanism, when serializing an object, it not only serializes the current object itself, but also serializes other objects referenced by the object, as well as other objects referenced by those other objects, and so on. Therefore, if an object contains member variables that are container class objects, and the containers contain elements that are also container class objects, the serialization process is more complex and expensive.

5. Impact serialization

In real-world applications, the default serialization mechanism cannot be used in some cases. For example, you want to ignore sensitive data during serialization, or simplify the serialization process. Several methods that affect serialization are described below.

5.1 Transient Keywords

When a field is declared as transient, the default serialization mechanism ignores the field. The age field in the person class is declared here as transient, as shown below.

public class Person implements Serializable {      ...      Transient private Integer age = null;      ...  } Then execute the simpleserial application with the following output: Arg constructor  

Visible, the Age field is not serialized.

5.2 WriteObject () method and ReadObject () method

For the above field that has been declared as transitive, is there any other way to make it serializable again, in addition to removing the transitive keyword? One way to do this is to add two methods to the person class: WriteObject () and ReadObject () as follows:

public class Person implements Serializable {      ...      Transient private Integer age = null;      ...       private void WriteObject (ObjectOutputStream out) throws IOException {          out.defaultwriteobject ();          Out.writeint (age);      }       private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {          in.defaultreadobject () ;          Age = In.readint ();      }  

The Defaultwriteobject () method in ObjectOutputStream is called first in the WriteObject () method, which executes the default serialization mechanism, as described in section 5.1, when the age field is ignored. The Writeint () method is then called to display the age field to the ObjectOutputStream. The function of ReadObject () is to read the object, and its principle is the same as the WriteObject () method. Once the simpleserial application is executed again, the following output will be available:

Arg constructor  

It must be noted that WriteObject () and ReadObject () are private methods, so how are they called? There is no doubt that reflection is used. See the Writeserialdata method in ObjectOutputStream and the Readserialdata method in ObjectInputStream for details.

5.3 Externalizable Interface

Either using the Transient keyword or using the writeobject () and ReadObject () methods are all based on the serialization of the Serializable interface. Another serialization interface,--externalizable, is provided in the JDK, after which the serialization mechanism based on the serializable interface is invalidated. At this point, the person class is modified as follows

public class Person implements externalizable {private String name = NULL;       Transient private Integer age = null;       Private Gender Gender = null;      Public person () {System.out.println ("None-arg constructor");          The public person (String name, Integer age, Gender Gender) {System.out.println ("Arg constructor");          THIS.name = name;          This.age = age;      This.gender = gender;          } private void WriteObject (ObjectOutputStream out) throws IOException {Out.defaultwriteobject ();      Out.writeint (age); } private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultread          Object ();      Age = In.readint (); } @Override public void writeexternal (ObjectOutput out) throws IOException {} @Override Public void Readexternal (ObjectInput in) throws IOException, ClassNotFoundException {} ...} When you execute the simpleserial program again, youResults are as follows: Arg constructor None-arg constructor [null, NULL, NULL]  

From this result, on the one hand, you can see that any of the fields in the person object are not serialized. On the other hand, if you're careful, you can also see that this serialization process calls the parameterless constructor of the person class.

Externalizable inherits from Serializable, and when the interface is used, the details of the serialization need to be done by the programmer. As shown above, the serialization behavior will not save/read any of the fields because the writeexternal () and Readexternal () methods do not do any processing. This is why the values of all the fields in the output result are empty.

In addition, when using externalizable for serialization, when the object is read, the parameterless constructor of the serialized class is called to create a new object, and the values of the fields of the saved object are then populated into the new object, respectively. This is why the parameterless constructor of the person class is called during this serialization. For this reason, the class implementing the Externalizable interface must provide an argument-free constructor, and its access rights are public.

Make further modifications to the person class above so that it can serialize the name and age fields, but ignore the gender field, as shown in the following code:

public class Person implements externalizable {private String name = NULL;       Transient private Integer age = null;       Private Gender Gender = null;      Public person () {System.out.println ("None-arg constructor");          The public person (String name, Integer age, Gender Gender) {System.out.println ("Arg constructor");          THIS.name = name;          This.age = age;      This.gender = gender;          } private void WriteObject (ObjectOutputStream out) throws IOException {Out.defaultwriteobject ();      Out.writeint (age); } private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultread          Object ();      Age = In.readint ();          } @Override public void writeexternal (ObjectOutput out) throws IOException {out.writeobject (name);      Out.writeint (age); } @Override public void Readexternal (ObjectInput in) throws IOException, Classnotfoundexception {name = (String) in.readobject ();      Age = In.readint (); }      ...  }  After executing the simpleserial, the following results are available: Arg constructor None-arg constructor [John, + null]

5.4 Readresolve () method

When we use singleton mode, it should be expected that an instance of a class should be unique, but if the class is serializable, the situation may be slightly different. At this point, the person class used in section 2nd is modified to implement the singleton pattern, as follows:

public class Person implements Serializable {       private static class Instanceholder {          private static final person in Statnce = new Person ("John", Gender.male);      }       public static Person getinstance () {          return instanceholder.instatnce;      }       Private String name = NULL;       Private Integer age = null;       Private Gender Gender = null;       Private person () {          System.out.println ("None-arg constructor");      }       Private person (String name, Integer age, Gender Gender) {          System.out.println ("Arg constructor");          this.name = name;          This.age = age;          This.gender = gender;      }      ...  

Also, to modify the Simpleserial application, it is possible to save/get the above singleton object and compare the object equality, as shown in the following code:

public class Simpleserial {public       static void Main (string[] args) throws Exception {          file File = new file ("person . Out ");          ObjectOutputStream oout = new ObjectOutputStream (new FileOutputStream (file));          Oout.writeobject (Person.getinstance ()); Save Singleton Object          oout.close ();           ObjectInputStream oin = new ObjectInputStream (new FileInputStream (file));          Object Newperson = Oin.readobject ();          Oin.close ();          System.out.println (Newperson);           System.out.println (person.getinstance () = = Newperson); Compares the obtained object to the singleton object in the person class for Equality      }  

After executing the above application, you will get the following results:

Arg constructor  [John, MALE]  

It is worth noting that the person object obtained from file person.out is not equal to the singleton object in the person class. In order to be able to maintain the characteristics of a singleton during the serialization process, you can add a readresolve () method to the person class to return the singleton object of person directly, as follows:

public class Person implements Serializable {       private static class Instanceholder {          private static final person in Statnce = new Person ("John", Gender.male);      }       public static Person getinstance () {          return instanceholder.instatnce;      }       Private String name = NULL;       Private Integer age = null;       Private Gender Gender = null;       Private person () {          System.out.println ("None-arg constructor");      }       Private person (String name, Integer age, Gender Gender) {          System.out.println ("Arg constructor");          this.name = name;          This.age = age;          This.gender = gender;      }       Private Object Readresolve () throws Objectstreamexception {          return instanceholder.instatnce;      }      ...  

After performing the simpleserial application in this section again, the following output will be:

Arg constructor  [John, MALE]  

Either implementing the Serializable interface or the Externalizable interface, the Readresolve () method is called when the object is read from the I/O stream. The object that was created in the deserialization process is replaced directly with the object returned in Readresolve ().

 

In-depth understanding of Java Object Serialization (reproduced)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.