Java's default serialization mechanism is very simple, and the serialized object does not need to be re-called by the constructor. However, in reality, we can expect that a part of the object does not need to be serialized,
Or after an object is restored, some internal sub-objects need to be re-created, so that the sub-object will not be serialized. In these cases, we can consider implementing the externalizable interface instead of the serializable interface.
To control the serialization process (we will talk about a simpler method later, through the transient method ). Externalizable interface extends serializable interface, and added two methods based on it: writeexternal () and readexternal ().
These two methods will be automatically called during serialization and deserialization restoration to execute some special operations. Package Java. io; import Java. io. objectoutput; import Java. io. objectinput; public interface externalizable extends Java. io. serializable {void writeexternal (objectoutput out) throws ioexception; void readexternal (objectinput in) throws ioexception, classnotfoundexception;} the following code demonstrates how to completely save and restore a package test of the externalizable object. serializable; import Java. io. externalizable; import Java. io. ioexception; import Java. Io. objectinput; import Java. io. objectoutput; public class blip implements externalizable {private int I; private string s; // public blip () not initialized {// The default constructor must exist and must be public system. out. println ("blip default constructor");} public blip (string S, int I) {// s, I is only initialized in the constructor with parameters. System. out. println ("blip with parameter constructor"); this. S = s; this. I = I;} Public String tostring () {return S + I;} @ override public void readexternal (objectinput in) throws ioexception, classnotfoundexception {system. out. println ("Call readexternal () method"); s = (string) in. readobject (); // during deserialization, You need to initialize s and I. Otherwise, only the default constructor is called and the values of S and I are not obtained. readint () ;}@ override public void writeexternal (objectoutput out) throws ioexcept Ion {system. out. println ("Call writeexternal () method"); out. writeobject (s); // if we do not write values of S and I, these values will not be obtained during deserialization. Out. writeint (I) ;}} package test. serializable; import Java. io. bytearrayinputstream; import Java. io. bytearrayoutputstream; import Java. io. ioexception; import Java. io. objectinputstream; import Java. io. objectoutputstream; public class externalizabletest {/*** @ Param ARGs * @ throws ioexception * @ throws classnotfoundexception */public static void main (string [] ARGs) throws ioexception, classnotfoundexception {system. out. println ("before serialization"); blip B = new blip ("this string is", 47); system. out. println (B); system. out. println ("serialization operation, writeobject"); bytearrayoutputstream out = new bytearrayoutputstream (); objectoutputstream OOS = new objectoutputstream (out); OOS. writeobject (B); system. out. println ("readobject after deserialization"); bytearrayinputstream in = new bytearrayinputstream (Out. tobytearray (); objectinputstream OIS = new objectinputstream (in); blip BB = (blip) Ois. readobject (); system. out. println (bb) ;}} the running result is as follows: Before serialization, blip carries the parameter constructor this string is 47 for serialization. After writeobject calls the writeexternal () method for deserialization, readobjectblip the default constructor calls the readexternal () method this string is 47. analysis result: In the blip class, fields s and I are only initialized in the second constructor, instead of being initialized in the default constructor, The writeextenal () method is called every time a writeobject is called,
In the writeextenal () method, we need to write the value of the current object to the stream. In each readobject () method, the default constructor is called. If we do not use readexternal ()
If s and I are initialized in the method, S is null, And I is 0. The following are several cases: 1) if we only modify writeexternal (), the method is as follows: @ override public void writeexternal (objectoutput out) throws ioexception {system. out. println ("Call writeexternal () method"); // out. writeobject (s); // out. writeint (I);} Then the running result is: Before serialization, blip carries the parameter constructor this string is 47 for serialization. After writeobject calls the writeexternal () method for deserialization, readobjectblip the default constructor calls the readexternal () method exception in thread "Main" Java. io. optionaldataexception at java. io. objectinputstream. readobject0 (objectinputstream. java: 1349) at java. io. objectinputstream. readobject (objectinputstream. java: 351) at test. serializable. blip. readexternal (blip. java: 34) at java. io. objectinputstream. readexternaldata (objectinputstream. java: 1792) at java. io. objectinputstream. readordinaryobject (objectinputstream. java: 1751) at java. io. objectinputstream. readobject0 (objectinputstream. java: 1329) at java. io. objectinputstream. readobject (objectinputstream. java: 351) at test. serializable. externalizabletest. main (externalizabletest. java: 28)
The reason is that we do not have writeobject in objectoutputstream, but in objectinputstream readobject 2) If we modify writeexternal () method as follows: @ override public void writeexternal (objectoutput out) throws ioexception {system. out. println ("Call writeexternal () method"); out. writeobject ("Custom"); out. writeint (250);} Then the running result is: Before serialization, blip carries the parameter constructor this string is 47 for serialization. After writeobject calls the writeexternal () method for deserialization, readobjectblip the default constructor calls the readexternal () method. For details, refer to 250. See no. The S and I obtained after deserialization are the data we customized in writeexternal (). 3) if we only modify the readexternal () method @ override public void readexternal (objectinput in) throws ioexception, classnotfoundexception {system. out. println ("Call readexternal () method"); // s = (string) in. readobject (); // I = in. readint ();} Then the running result is: Before serialization, blip carries the parameter constructor this string is 47 for serialization. After writeobject calls the writeexternal () method for deserialization, readobjectblip default constructor call readexternal () method null0 see? The last line prints null0, indicating that s and I are not initialized. 4) if we delete the default constructor of blip, or do not set its permission to public/Public blip () {// The default constructor must have, it must be public // system. out. println ("blip default constructor"); // or blip () {// The default constructor must exist and must be public system. out. println ("blip default constructor");} the running result is as follows: Before serialization, blip has a parameter constructor. This string is 47. After writeobject calls the writeexternal () method for deserialization, readobjectexception in thread "Main" Java. io. invalidclassexception: test. serializable. blip; test. serializable. blip; no valid Constructor at java. io. objectstreamclass. checkdeserialize (objectstreamclass. java: 713) at java. io. objectinputstream. readordinaryobject (objectinputstream. java: 1733) at java. io. objectinputstream. readobject0 (objectinputstream. java: 1329) at java. io. objectinputstream. readobject (objectinputstream. java: 351) at test. serializable. externalizabletest. main (externalizabletest. java: 28) caused by: Java. io. invalid Classexception: test. serializable. blip; no valid constructor at java. io. objectstreamclass. <init> (objectstreamclass. java: 471) at java. io. objectstreamclass. lookup (objectstreamclass. java: 310) at java. io. objectoutputstream. writeobject0 (objectoutputstream. java: 1106) at java. io. objectoutputstream. writeobject (objectoutputstream. java: 326) at test. serializable. externalizabletest. main (externalizabletest. jav A: 24) during deserialization, an invalid constructor error occurs, it can be seen that a default constructor with the public permission must be available. (If a non-default constructor with parameters exists, the default constructor must be displayed, if there is no non-default constructor, the default constructor can be written out without being displayed.) in this way, the externalizable object can produce correct behavior. To sum up the usage of the externalizable object: Unlike the serizable object, the use of externalizabled means that nothing can be automatically serialized. for normal operation, we need () to manually complete serialization. For an externalizabled object,
The default constructor of an object is called (including the fields initialized at the time of definition), and then readexternal () is called. data must be restored manually in this method.