Serialization analysis of Java ArrayList

Source: Internet
Author: User

First, Introduction

The so-called Java serialization and deserialization, serialization is to keep Java objects in one form, such as storage to the hard disk, or for transmission. Deserialization is a reverse process of serialization.

Java specifies that the object being serialized must implement the Java.io.Serializable interface, and the target ArrayList of our analysis also implements the interface.

Through the analysis of the ArrayList source code, you can know that the ArrayList data store is dependent on the Elementdata array, which is declared as:

Transient object[] elementdata;
Note that transient modifies the elementdata array.
1, first look at the role of transient keyword

We all know that an object can be serialized as long as the Serilizable interface is implemented, and the Java serialization pattern provides developers with a lot of convenience, and we don't have to relate to the process of specific serialization, as long as this class implements the Serilizable interface, All properties and methods of this class are automatically serialized.

However, in the actual development process, we often encounter such a problem, some properties of this class need to serialize, and other attributes do not need to be serialized, for example, if a user has some sensitive information (such as password, bank card number, etc.), for security purposes, do not want to operate in the network (mainly involved in serialization operations, Local serialization cache is also applicable), the variable that corresponds to this information can be added to the transient keyword. In other words, the life cycle of this field is only stored in the caller's memory and is not persisted to disk.

In short, the Java transient keyword is convenient for us, you only need to implement the Serilizable interface, will not need to serialize the property before adding the keyword transient, when serializing the object, this property will not be serialized to the specified destination.

For details, see: Java Transient keywords use small notes

Since Elementdata is modified by transient, it is logically impossible to serialize, so how does ArrayList solve the problem of serialization?

Second, the serialization of work flow

The Java.io.Serializable class enables its serialization functionality by implementing the interface. To serialize an object, it must be associated with a certain object output/input stream, save the state of the object through the object output stream, and restore the object state through the object input stream.

Classes that require special handling during serialization and deserialization must use the following exact signatures to implement special methods:

private void WriteObject (Java.io.ObjectOutputStream out) throws IOException

private void ReadObject (Java.io.ObjectInputStream in) throws IOException, ClassNotFoundException

1. Object serialization Steps

A) write

    • First, create a outputstream output stream;
    • Then create a objectoutputstream output stream and pass in the OutputStream output stream object;
    • Finally, the WriteObject () method of the ObjectOutputStream object is called to write the object state information to OutputStream.

b) Read

    • First, create a inputstream input stream;
    • Then create a objectinputstream input stream and pass in the InputStream input stream object;
    • Finally, the ReadObject () method of the ObjectInputStream object is called to read the object state information from the InputStream.

To illustrate:

public class Box implements Serializable {
Private static final long serialversionuid = -3450064362986273896l;

private int width;
private int height;

public static void Main (string[] args) {
Box mybox=new box ();
Mybox.setwidth (50);
Mybox.setheight (30);
try {
FileOutputStream fs=new FileOutputStream ("F:\\foo.ser");
ObjectOutputStream os=new ObjectOutputStream (FS);
Os.writeobject (Mybox);
Os.close ();
FileInputStream fi=new FileInputStream ("F:\\foo.ser");
ObjectInputStream oi=new ObjectInputStream (FI);
Box box= (Box) oi.readobject ();
Oi.close ();
System.out.println (box.height+ "," +box.width);
} catch (Exception e) {
E.printstacktrace ();
}
}

public int getwidth () {
return width;
}
public void setwidth (int width) {
This.width = width;
}
public int getheight () {
return height;
}
public void setheight (int height) {
This.height = height;
}
}
Iii. ArrayList resolving serialization 1, serialization

As can be seen from the serialized workflow above, to serialize an object, write the object state information using the WriteObject () method of the ObjectOutputStream object output stream, and use the ReadObject () method to read the information.

Is it possible to call the WriteObject () method of the ObjectOutputStream object in ArrayList to write the value of Elementdata to the output stream?

See Source:

private void WriteObject (Java.io.ObjectOutputStream s) throws Java.io.IOException
{
Write out element count, and any hidden stuff
int expectedmodcount = Modcount;
S.defaultwriteobject ();
Write out size as capacity-behavioural compatibility with clone ()
S.writeint (size);
Write elements in the proper order.
for (int i = 0; i < size; i++)
{
S.writeobject (Elementdata[i]);
}
if (modcount! = expectedmodcount)
{
throw new Concurrentmodificationexception ();
}
}

Although Elementdata is modified by transient, it cannot be serialized, but we can take its value out and write the value to the output stream.

Fragment 1 its function is equivalent to fragment 2
S.writeobject (Elementdata[i]); When the value is passed, it is the formal parameter assigned to the S.writeobject () by the argument Elementdata[i]
Episode 2
Object temp = new Object (); Temp hasn't been transient modified.
temp = Elementdata[i];
S.writeobject (temp);

2, deserialization ArrayList the principle of deserialization, see source code:
private void ReadObject (Java.io.ObjectInputStream s) throws Java.io.IOException, ClassNotFoundException
{
Elementdata = Empty_elementdata;
Read in size, and any hidden stuff
S.defaultreadobject ();
Read in capacity
S.readint (); Ignored
if (Size > 0)
{
Be-like clone (), allocate array based upon size not capacity
Ensurecapacityinternal (size);
Object[] A = Elementdata;
Read in all elements in the proper order.
for (int i = 0; i < size; i++)
{
A[i] = S.readobject ();
}
}
}
From the above source and another problem, these methods are defined as private, when can be called? 3, call if a class not only implements the serializable interface, but also defines the ReadObject (ObjectInputStream in) and WriteObject (ObjectOutputStream out) methods, Then the serialization and deserialization will be as follows:

ObjectOutputStream calls this class's WriteObject method for serialization, ObjectInputStream calls the corresponding ReadObject method for deserialization.

Is that the way things are? Let's do a little experiment to Yue Heyue.
Lab 1:

public class Testserialization implements Serializable
{
private transient int num;

public int Getnum ()
{
return num;
}

public void setnum (int num)
{
This.num = num;
}

private void WriteObject (Java.io.ObjectOutputStream s)
Throws Java.io.IOException
{
S.defaultwriteobject ();
S.writeobject (num);
System.out.println ("WriteObject of" +this.getclass (). GetName ());
}

private void ReadObject (Java.io.ObjectInputStream s)
Throws Java.io.IOException, ClassNotFoundException
{
S.defaultreadobject ();
num = (Integer) s.readobject ();
System.out.println ("ReadObject of" +this.getclass (). GetName ());
}

public static void Main (string[] args)
{
Testserialization test = new Testserialization ();
Test.setnum (10);
System.out.println ("Value before serialization:" +test.getnum ());
Write
Try
{
ObjectOutputStream outputstream = new ObjectOutputStream (
New FileOutputStream ("d:\\test.tmp"));
Outputstream.writeobject (test);
} catch (FileNotFoundException e)
{
E.printstacktrace ();
} catch (IOException e)
{
E.printstacktrace ();
}
Read
Try
{
ObjectInputStream oinputstream = new ObjectInputStream (
New FileInputStream ("d:\\test.tmp"));
Try
{
Testserialization atest = (testserialization) oinputstream.readobject ();
System.out.println ("read the serialized Value:" +atest.getnum ());
} catch (ClassNotFoundException e)
{
E.printstacktrace ();
}
} catch (FileNotFoundException e)
{
E.printstacktrace ();
} catch (IOException e)
{
E.printstacktrace ();
}
}
}
Output:

Value before serialization: 10
WriteObject of Testserialization
ReadObject of Testserialization
Read serialized value: 10

The experimental results show that this is true: ObjectOutputStream calls the class's WriteObject method for serialization, and ObjectInputStream calls the corresponding ReadObject method for deserialization.
So how does ObjectOutputStream know if a class implements the WriteObject method? And how do you automatically invoke the WriteObject method of the class? The answer is: it is done through a reflection mechanism. Part of the answer: ObjectOutputStream's writeobject to do again what things. It will be based on the ArrayList object passed in to get class, and then packaged into ObjectStreamClass, in Writeserialdata method, will call ObjectStreamClass Invokewriteobject method, the most important code is as follows:
Writeobjectmethod.invoke (obj, new object[]{out});
The instance variable Writeobjectmethod is assigned as follows:
Writeobjectmethod = Getprivatemethod (cl, "WriteObject",
New class[] {Objectoutputstream.class},
Void.type);

private static Method Getprivatemethod (Class cl, String name,
Class[] argtypes, Class returntype)
{
Try
{
Method meth = Cl.getdeclaredmethod (name, argtypes);
To access the private method of an object by reflection
Meth.setaccessible (TRUE);
int mods = Meth.getmodifiers ();
Return ((meth.getreturntype () = = ReturnType)
&& ((mods & modifier.static) = = 0) && ((Mods & modifier.private)! = 0))? Meth
: null;
} catch (Nosuchmethodexception ex)
{
return null;
}
}
In doing the experiment, we found a problem, that is why we need s.defaultwriteobject (), and S.defaultreadobject (); readObject(ObjectInputStream o)and writeObject(ObjectOutputStream o)What about before? They function as follows: 1, It reads and writes all the non transientFields of the class respectively.2, these methods also helps in backward and future compatibility. If in the future you add some non-transientfield to the class and you is trying to deserialize it by the older version of class then the Defaultreadobject () method Would neglect the newly added field, similarly if you deserialize the old serialized object by the new version then the new Non transient field would take the default value from JVM Four, why use transient decorated elementdata?

Now that you want to serialize the fields of the ArrayList (which is going to be elementdata serialized), why use transient to decorate the elementdata?

Recalling the ArrayList automatic expansion mechanism, the Elementdata array is equivalent to the container, when the container is insufficient to expand the capacity, but the container capacity is often greater than or equal to the number of elements stored in ArrayList.

For example, now that there are actually 8 elements, the capacity of the Elementdata array might be 8x1.5=12, and if the Elementdata array is serialized directly, then the space of 4 elements will be wasted, especially if the number of elements is very large, this waste is very uneconomical.

So the designer of ArrayList designed the Elementdata as transient, then serialized it manually in the WriteObject method, and serialized only those elements that were actually stored, not the entire array.

See Source:

Write elements in the proper order.

{
S.writeobject (Elementdata[i]);
}
From the source, you can observe that the loop is using i<size instead of i<elementdata.length, stating that when serializing, only those elements that are actually stored, not the entire array.

Reference:

1,java.io.Serializable analysis

2, Java serializable in-depth understanding

3, ArrayList source analysis--how to achieve serializable

4. Summary of Java serialization and deserialization sessions

Serialization analysis of Java ArrayList

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.