"Summarize" Java serialization you don't know

Source: Internet
Author: User
Tags class definition object serialization

As we all know, Java serialization allows us to record the state of the object at runtime (the value of the object instance field), which is what we often call object Persistence . This process is actually very complex, and here we have a good understanding of the object serialization of Java.

1, First of all, we have to understand thatJava object Serialization is the object's instance domain data (including private private domain) to persist storage. Instead of storing the class information that the entire object belongs to. in fact, we understand the JVM and we can understand that. In fact, the objects stored in the heap contain the instance domain data values and the addresses that point to the class information, and the class information that the object belongs to is stored in the method area. When we want to deserialize the persistent layer data into objects, we just need to store the instance domain data values in the newly created object.

2, We all know that all classes to be serialized must implement the Serializable interface. but not all of the classes can be serialized? Of course not, think about serialization can make it easy for us to touch the object's private data domain, this is how dangerous loophole! To summarize, there are four types of class objects in the JDK that are absolutely not serializable.

(1) Classes that are too dependent on the underlying implementation (too closely tied to native code). Like Java.util.zip.Deflater.

(2) The state of an object depends on the inside of the virtual machine and the constantly changing runtime environment. Like Java.lang.Thread, Java.io.InputStream.
(3) related to potential security issues. For example: Java.lang.SecurityManager, Java.security.MessageDigest
(4) All static domain classes, no object instance data. You know that the static domain itself is also stored in the method area.

3, custom classes as long as the implementation of the serializable interface, is it possible to serialize it? of course not, look at the following example:

 class  Employee implements   serializable{ private  zipfile zf=null<         /span> this . Zf=ZF;  }}objectoutputstream oout  =new  ObjectOutputStream (new  FileInputStream (new  File ("Aaa.txt"  new  Employee ( Span style= "color: #0000ff;" >new  zipfile ("c://..")); 

We will find that after running the java.io.NotSerializableException is thrown: java.util.zip.ZipFile. Obviously, if you want to serialize an employee object, you must also serialize its data field ZipFile object, which is not serializable in the JDK. Therefore, objects that contain non-serializable object fields are also not serializable. In fact, this is not impossible, we are in the 6th meeting below.

4. After the serializable class is successfully serialized, is it possible to deserialize it? (This is the default in the same environment, and the class definition will never change, that is, compatibility is met.) In the following we will discuss the incompatibility of serialization). The answer is not necessarily oh! Let's look at one of the following:

//Parent Class object cannot be serializedclassemployee{PrivateString name; Employee (String N) { This. name=N; }     PublicString GetName () {return  This. Name; }}//subclass objects can be serializedclassManagerextendsEmployeeImplementsserializable{Private intID; Manager (String name,intID) {        Super(name);  This. id=ID; }}//serialization and deserialization testing Public Static voidMain (string[] args)throwsIOException, classnotfoundexception{file file=NewFile ("E:/aaa.txt"); ObjectOutputStream oout=NewObjectOutputStream (Newfileoutputstream (file)); Oout.writeobject (NewManager ("Amao", 123));    Oout.close (); System.out.println ("Serialization succeeded"); ObjectInputStream oin=NewObjectInputStream (Newfileinputstream (file)); Object o=Oin.readobject ();    Oin.close (); System.out.println ("Deserialization succeeded:" +( (Manager) o). GetName ());}

The running result of the program is: Print out "serialization success" after the throw java.io.InvalidClassException: Manager; Manager; No valid constructor. Why does this happen? Obviously, serialization only writes the data domain ID of the manager class object to the file, but during deserialization, a new manager object is created in the heap. We all know that the establishment of any class object first requires the constructor of the parent class to initialize the parent class, but unfortunately there is no name data for the parent class employee in the serialization file, and the employee (String) constructor is called because there is no data for the exception. Since there is no data, can you call the parameterless constructor? The fact is that, if there is an employee () parameterless constructor, there will be no exception, but---"deserialization succeeded: null" when printing was performed.

To summarize: If there is a class in all the superclass of the current class that is not serializable, there is no parameterless constructor. Then the current class cannot be deserialized. If you have a parameterless constructor, the data fields that this superclass deserializes will be null or 0,false, and so on.

5, serialization of compatibility issues!

Class definitions are likely to be kept artificially updated (such as JDK1.1 to JDK1.2 Hashtable changes). The old class object that was previously serialized would probably no longer be deserialized into a new class object. This is a serialization compatibility issue, and in a strict sense, changing all parts of a class except static and transient will cause compatibility issues. The JDK uses a stream unique identifier (SUID) to identify compatibility. Suid is a 64-bit hash value that computes the class name, interface name, method, and data field through complex functions. This value is stored in a static domain within the class:

Private static final Long Serialversionuid = 3487495895819393L

As soon as you change the definition of the class slightly, the suid of this class will change, and we'll look at the following procedure:

//employee prior to modificationclassEmployeeImplementsserializable{PrivateString name; Employee (String N) { This. name=N; }     PublicString GetName () {return  This. Name; }}//test, print suid=5135178525467874279lLongSerialversionuid=objectstreamclass.lookup (Class.forName ("Employee") . Getserialversionuid (); System.out.println (serialversionuid);//Modified EmployeeclassEmployeeImplementsserializable{PrivateString name1;//Note that the name of the data field is changed slightly hereEmployee (String N) { This. name1=N; }     PublicString GetName () {return  This. name1; }}//test, print suid=-2226350316230217613lLongSerialversionuid=objectstreamclass.lookup (Class.forName ("Employee") . Getserialversionuid (); System.out.println (serialversionuid);

Two Tests suid are different, but you can try if the Name field is static or transient declared, changing the domain name will not affect SUID.

It is clear that the JVM detects the incompatibility between the serialized object and the deserialized object by detecting the difference between the new and old class suid. Throw java.io.InvalidClassException: Employee; Local class Incompatible:

Many times, the change in class definitions is imperative, but does not want to have serialization incompatibilities. We can then give a definite long value by serialversionuid the definition shown in the class. This will escape the JVM's default compatibility check. However, if the change in the data domain name results in deserialization, the changed data field can only get the default null or 0 or false value.

6 . In the 3rd above, I talked about an employee's column that cannot be serialized successfully, because it contains a data field that cannot be serialized by a ZipFile object reference. but there are times when we really want to serialize the local file path of the ZipFile, is there a real way out of it? Here we will be a very useful application.

When we need to serialize a class object using the WriteObject (object) method, we first write the data fields of each superclass according to the inheritance hierarchy from high to low for all the superclass of the class object. Who can guarantee that each superclass implements the serializable interface? In fact, for these classes that cannot be serialized, the JVM checks to see if the classes have such a method:

private void WriteObject (ObjectOutputStream out) throws IOException
If so, the JVM calls this method and still serializes the data fields of that class. Let's take a look at the implementation of this section in the ObjectOutputStream class of the JDK (I'm only listing the execution process in the source code):

//The following method is called from top to bottomwriteobject (Object);//the WriteObject method of ObjectOutputStream Public Final voidWriteObject (Object obj)throwsIOException {writeObject0 (obj,false);}//ObjectOutputStream, the implementation of the underlying write objectPrivate voidWriteObject0 (Object obj,Booleanunshared) {       if(objinstanceofSerializable) {writeordinaryobject (obj, desc, unshared);}//ObjectOutputStreamPrivate voidWriteordinaryobject (Object obj, ObjectStreamClass desc,Booleanunshared) {writeserialdata (obj, desc);}//ObjectOutputStream, for each serializable class of a superclass to a subclass, writes out the data field Private voidWriteserialdata (Object obj, ObjectStreamClass desc)throwsioexception{//If there is a writeobject (ObjectOutputStream) method in the class, the call is made through the underlying         if(Slotdesc.haswriteobjectmethod ()) {slotdesc.invokewriteobject (obj), This); }//If you do not have this method, the default method for writing the class data field is used.          Else{//This method writes out the data fields in the Serializable object, but throws an exception if the data field is non-serializable and has no writeobject (ObjectOutputStream) method for the class object. defaultwritefields (obj, slotdesc); }}

The Writeserialdata () method in ObjectOutputStream illustrates the potential execution mechanism of the private method that the JVM checks for writeobject (ObjectOutputStream out) . This means that we can construct this method so that some data fields of a class that are not serializable can be serialized. Let's start with a serializable transformation of ZipFile!

//a custom serializable ZipFile, which, of course, cannot inherit zipfile from the JDK, otherwise serialization will not be possible. classSerializablezipfileImplementsserializable{ PublicZipFile ZF; //contains a ZipFile objectSerializablezipfile (String filename)throwsioexception{ZF=Newzipfile (filename); }    //The file name in ZipFile is serialized because it is of type string    Private voidWriteObject (ObjectOutputStream out)throwsioexception{Out.writeobject (Zf.getname ()); }    //corresponding, the JVM also checks for a similar private method during deserialization.     Private voidReadObject (ObjectInputStream in)throwsioexception,classnotfoundexception{String filename=(String) in.readobject (); ZF=Newzipfile (filename); }}//Test Public Static voidMain (string[] args)throwsIOException, classnotfoundexception{//Serialization ofFile file=NewFile ("E:/aaa.txt"); ObjectOutputStream oout=NewObjectOutputStream (Newfileoutputstream (file)); Oout.writeobject (NewSerializablezipfile ("E:/aaa.zip"));    Oout.close (); System.out.println ("Serialization succeeded"); //deserializationObjectInputStream oin=NewObjectInputStream (Newfileinputstream (file)); Object o=Oin.readobject ();    Oin.close (); System.out.println ("Deserialization succeeded:" +((serializablezipfile) O). Zf.getname ());}//serialization succeeds//deserialization succeeded: E:\aaa.zip

"Summarize" Java serialization you don't know

Related Article

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.