Serialization and deserialization of Java objects

Source: Internet
Author: User
Tags assert serialization thread class

Objective

Serialization and deserialization do not seem to be used much, but it is critical to use it because there is a problem with a little attention. Where is the serialized application scenario? Data is stored and transmitted, of course. such as caching, you need to re-engrave the object to the hard disk storage, even if the power loss can be re-serialized recovery. The following is a simple understanding of serialization usage and considerations.

How to serialize

To serialize an object in Java, you must implement an Serializable interface. It can then be persisted and deserialized. Here is a simple usage.

Project Test Code:
Https://github.com/Ryan-Miao/someTest/blob/master/src/main/java/com/test/java/serial/TestSerialize.java

We give a test class:

Package com.test.java.serial;import Lombok. Builder;import Lombok. Data;import java.io.Serializable;/** * @authorRyan Miao */@Data@Builder Public classFooImplementsSerializable {Private Static FinalString LOGGER ="Logger"; Public Static FinalString pub_static_final ="Publicstaticfinal"; Public StaticString pub_static; PublicString FA;PrivateString FB;transient  PublicString Ta;transient PrivateString TB;}

Then, test whether the serialized and deserialized data is missing.

 Public classtestserialize {Private Static FinalString filename ="D:/test.txt";@Test     Public void Testser()throwsIOException, ClassNotFoundException {FinalFoo foo = foo.Builder()                .FA("FA")                .FB("FB")                .Ta("Ta")                .TB("TB")                .Build(); Foo.pub_static="Test"; ObjectOutputStream OS =NewObjectOutputStream (NewFileOutputStream (filename)); Os.writeobject(foo); Os.Flush(); Os.Close(); }@Test     Public void Testread()throwsIOException, classnotfoundexception {ObjectInputStream is =NewObjectInputStream (NewFileInputStream (filename)); Foo foo2 = (foo) is.ReadObject(); Is.Close(); Assert.assertequals("FA", Foo2.GETFA()); Assert.assertequals("FB", Foo2.GETFB()); Assert.assertequals(NULL, Foo2.Getta()); Assert.assertequals(NULL, Foo2.GETTB()); Assert.Assertnull(Foo2.pub_static); }}

Obviously, the transient modified fields cannot be serialized, and as for static fields, there is no test, but be clear. Static fields are only related to class classes, and are not instance dependent. The serialization is for instance, so there is no difference between the content. So what does the data look like after the static field is deserialized? Of course, the class variable itself should look like. If it is not initialized, it is the default value, and the result in this test is null.

Why can I serialize

We can serialize as long as it's implemented Serialiable , so why? View ObjectOutputStream the writeObject method.

//Remaining casesif(objinstanceofString) {writestring((String) obj, unshared);}Else if(CL.IsArray()) {Writearray(obj, desc, unshared);}Else if(objinstanceofEnum) {Writeenum((enum<?>) obj, desc, unshared);}Else if(objinstanceofSerializable) {Writeordinaryobject(obj, desc, unshared);}Else{if(Extendeddebuginfo) {Throw NewNotserializableexception (CL.GetName() +"\ n"+ Debuginfostack.toString()); }Else{Throw NewNotserializableexception (CL.GetName()); }}

Obviously, the processing is only for string,enum and serializable, so it is necessary to implement this interface in order to serialize. Of course, string and Enum also implement Serializable.

How to customize serialization, why ArrayList in the Java base Class library, etc. can be serialized with transient

A simple object, for a field that you do not want to serialize, as long as it is declared as transient good. And sometimes, I want to serialize the partial fields after processing. For example, the data stored in ArrayList transient Object[] elementData; . We know that ArrayList can be serialized, the root of which is the custom here. Follow the ObjectOutputStream source code, know that the custom execution part can be verified.

Entrance: Java.io.objectoutputstream#writeobject

publicfinalvoidwriteObjectthrows IOException {    if (enableOverride) {        writeObjectOverride(obj);        return;    }    try {        writeObject0false);    catch (IOException ex) {        if0) {            writeFatalException(ex);        }        throw ex;    }}

Then, the core approach

Private void writeObject0(Object obj,Booleanunshared)throwsioexception{BooleanOldmode = bout.Setblockdatamode(false);d epth++;Try{//omit several lines         for(;;) {//omit several linesdesc = ObjectStreamClass.Lookup(CL,true);//omit several lines}//omit several lines        if(objinstanceofString) {writestring((String) obj, unshared); }Else if(CL.IsArray()) {Writearray(obj, desc, unshared); }Else if(objinstanceofEnum) {Writeenum((enum<?>) obj, desc, unshared); }Else if(objinstanceofSerializable) {Writeordinaryobject(obj, desc, unshared); }Else{//....}    }finally{depth--; Bout.Setblockdatamode(Oldmode); }}

Here, it is obvious to see that the real execution serialization code is writeOrdinaryObject(obj, desc, unshared); . But just trace it in. There are many initialized fields in the process that were previously done. So, first sell a xiaoguanzi, look at the previously initialized section, just find the field we want to initialize.

Enterdesc = ObjectStreamClass.lookup(cl, true);

staticlookupboolean all) {    //省略若干行    ifnull) {        try {            new ObjectStreamClass(cl);        catch (Throwable th) {            entry = th;        }        //.....    }    //省略若干行}

Enter entry = new ObjectStreamClass(cl); here is the real initialization place, the previously omitted code is cache processing, of course cache used by Concurrenthashmap.

private ObjectStreamClass(final Class<?> cl) {    //省略无数行以及括号    getPrivateMethod"writeObject",                            new Class<?>[] { ObjectOutputStream.class },                            Void.TYPE);    getPrivateMethod"readObject",                            new Class<?>[] { ObjectInputStream.class },                            Void.TYPE);    //省略无数行

Yes, it took so much effort to find these two method. By reflection, the two private methods to the target class are writeObject obtained readObject . These two are the custom methods.

Once the initialization is complete, we will continue with the serialized code. Back to just the core method, find writeOrdinaryObject(obj, desc, unshared); , enter, and then, continue to find writeSerialData(obj, desc); , here is the code that really executes the serialization.

Private void Writeserialdata(Object obj, ObjectStreamClass desc)throwsioexception{ObjectStreamClass.Classdataslot[] Slots = desc.Getclassdatalayout(); for(inti =0; I < slots.length; i++) {ObjectStreamClass Slotdesc = slots[i].desc;if(Slotdesc.Haswriteobjectmethod()) {//....            Try{Curcontext =New Serialcallbackcontext(obj, Slotdesc); Bout.Setblockdatamode(true); Slotdesc.Invokewriteobject(obj, This); Bout.Setblockdatamode(false); Bout.WriteByte(Tc_endblockdata); }finally{//...} curput = Oldput; }Else{Defaultwritefields(obj, Slotdesc); }    }}

It is clear that the method is initialized, and if so, it is writeObject called directly, and none is processed by default. Here, after the trace, I want to customize the serialization as long as the rewrite writeObject , both readObject methods can be.

Let's see how ArrayList did it.
Private void writeobject(java.io.ObjectOutputStreamSthrowsJava.io.IOException{//Write out element count, and any hidden stuff    intExpectedmodcount = Modcount; S.Defaultwriteobject();//Write out size as capacity-behavioural compatibility with clone ()S.Writeint(size);//Write out all elements in the proper order.     for(intI=0; i<size; i++) {s.writeobject(Elementdata[i]); }if(Modcount! = expectedmodcount) {Throw NewConcurrentmodificationexception (); }}

Because arrays are set to not allow serialization, the other information is serialized by default, and the contents of the array are processed separately, and the elements are written next to each other. Then, the corresponding reading method should also be changed.

Private void ReadObject(java.io.ObjectInputStreamSthrowsJava.io.IOException, classnotfoundexception {elementdata = Empty_elementdata;//Read in size, and any hidden stuffS.Defaultreadobject();//Read in capacityS.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(intI=0; i<size; i++) {A[i] = s.ReadObject(); }    }}

Why do you do this? Because the array element has a lot of free space, it doesn't need to be serialized. By customizing this, you can save space by serializing the elements you need.

Serialversionuid Why there are, some not, when to use, what is the meaning of

The following are from: https://www.cnblogs.com/ouym/p/6654798.html

What is Serialversionuid?

Serialversionuid: "Serialized version uniform identifier" (serial versions universal identifier), referred to as UID

Serialversionuid must be defined in this form: static final long serialversionuid = XxxL;

Serialversionuid is used to indicate compatibility between different versions of a class. There are two ways to build: One is the default of 1L, and the other is to generate a 64-bit hash field based on the class name, interface name, member method, and property.

Why to declare Serialversionuid

Java.io.ObjectOutputStream represents an object output stream, and its writeobject (object obj) method serializes the Obj object specified by the parameter and writes the resulting sequence of bytes to a target output stream. Java.io.ObjectInputStream represents an object input stream, and its readobject () method reads a sequence of bytes from a source input stream, deserializes them into an object, and returns them.

Only objects of a class that implement the serializable or Externalizable interface can be serialized.

The Externalizable interface inherits from the serializable interface, and the class that implements the Externalizable interface controls the serialization behavior entirely by itself, whereas classes that implement the serializable interface can take the default serialization method. Any class that implements the Serializable interface has a static variable that represents the serialized version identifier:private static final long serialVersionUID;

The default value of the Serialversionuid class is entirely dependent on the implementation of the Java compiler, which, for the same class, is compiled with different Java compilers, which can lead to different serialversionuid. There are two ways to explicitly define SERIALVERSIONUID:

    1. In some cases, you want different versions of the class to be serializable compatible, so you need to ensure that different versions of the class have the same serialversionuid, and in some cases, you don't want different versions of the class to be serializable compatible.
      It is therefore necessary to ensure that different versions of the class have different serialversionuid.
    2. When you serialize a class instance and want to change a field or add a field without setting serialversionuid, any changes will result in the inability to deserialize the old instance and throw an exception when deserializing.
      If you add serialversionuid, the newly added or changed field value will be set to the initialization value (the object is null, the base type is the corresponding initial default value) when the deserialization is old, and the field is deleted without setting.
Precautions
    1. When serializing, only the state of the object is saved, regardless of the object's method;
    2. When a parent class implements serialization, the subclass is automatically serialized, and no explicit implementation of the serializable interface is required;
    3. When an instance variable of an object refers to another object, the object is serialized as well.
    4. Not all objects can be serialized, and there are a number of reasons why not, such as:

      1. Security reasons, such as an object has Private,public and other fields, for a transmission of objects, such as writing to a file, or RMI transmission, etc., during the serialization of the transfer process, the object's private domain is not protected.
      2. Resource allocation reasons, such as the Socket,thread class, can be serialized, transmitted or saved, and cannot be re-allocated, and there is no need to implement this.
Reference
    • Understanding and summarizing Java Serializable (serialization)
    • The role of Serialversionuid
    • Java transient keywords use small notes
    • Why is Elementdata transient modified in ArrayList?

Serialization and deserialization of Java objects

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.