The serialization mechanism in Java is implemented in two ways:
One is to implement the Serializable interface
The other is to implement the Externalizable interface
Difference:
Implementing the Serializable interface
1 The system automatically stores the necessary information
2 Java built-in support, easy to implement, just implement the interface, without any code support
3 performance is slightly worse
Implementing the Externalizable Interface
1 Programmers decide what information to store
2 provides only two empty methods, implementing the interface must provide implementations for two null methods
3 Slightly better performance
Because the implementation of the Externalizable interface leads to increased programming complexity, most of the time the implementation of the serializable interface is used to achieve serialization.
An example is given below
Public class Personbean implements Serializable { PrivateString name;Private intAge PublicStringGetName() {returnName } Public void SetName(String name) { This. name = name; } Public int Getage() {returnAge } Public void Setage(intAge) { This. Age = Age; }@Override PublicStringtoString() {return "Name="+ This. Name +", age="+ This. Age; }}
This is a Personbean class, so simple that the serialization of the Personbean class has been implemented.
You can use the ObjectInputStream, ObjectOutputStream classes to write and read objects.
The code is as follows:
Public Static void Main(string[] args) {Personbean PersonBean1 =NewPersonbean (); Personbean1.setname ("Long"); Personbean1.setage ( -); Personbean personBean2 =NewPersonbean (); Personbean2.setname ("Fei"); Personbean2.setage ( -); ObjectOutputStream ObjectOutputStream =NULL; ObjectInputStream ObjectInputStream =NULL; String Path ="D:\\Program Files (x86) \\ADT\\workspace\\JavaIO\\demoTest.txt";Try{FileOutputStream FileOutputStream =NewFileOutputStream (path); FileInputStream FileInputStream =NewFileInputStream (path); ObjectOutputStream =NewObjectOutputStream (FileOutputStream); Objectoutputstream.writeobject (PERSONBEAN1); Objectoutputstream.writeobject (PERSONBEAN2); ObjectInputStream =NewObjectInputStream (FileInputStream); Personbean personBean3 = (Personbean) objectinputstream.readobject (); Personbean PersonBean4 = (Personbean) objectinputstream.readobject (); System. out. println (Personbean3.tostring ()); System. out. println (Personbean4.tostring ()); }Catch(IOException | ClassNotFoundException e) {e.printstacktrace (); }finally{if(ObjectOutputStream! =NULL) {Try{Objectoutputstream.close (); }Catch(IOException e) {E.printstacktrace (); } } } }}
Result diagram:
Allow custom serialization in Java, provides a modifier transient, which can only be decorated with field fields, cannot be decorated with methods and classes, and the effect of this modifier is to completely isolate the modified field from the serialization mechanism. This causes the field value to not be obtained when deserializing the reply to the Java object.
Now the age field of the Peronbean class is decorated with this modifier, and the other code remains the following:
publicclass PersonBean implements Serializable { private String name; privatetransientint age; ..............
Then run the program demo, the results are as follows:
See the results you should understand the meaning of the modifier.
The custom serialization mechanism is not as simple as this and can be more powerful.
Classes that require special handling during serialization and deserialization provide a special signature method, which is used to implement custom serialization
privatevoidwriteObjectthrows IOExceptionprivatevoidreadObjectthrows IOException,ClassNotFoundExceptionprivatevoidreadObjectNoDatathrows ObjectStreamException
The WriteObject method is responsible for writing a specific tired instance state, and the ReadObject method can reply to it
When the sequence stream is incomplete, the Readobjectnodata method can be used to correctly initialize the deserialized object: for example, the receiver uses a version of the deserialization class that is not used by the sender, or the receiver version extension class is not a class that relaxes the version extension, or if the serialization stream is tampered with. The system will call the Readobjectnodata method class to initialize the deserialized object.
The following overrides the Personbean class, custom serialization, and the following code:
Public class Personbean implements Serializable { PrivateString name;Private transient intAge PublicStringGetName() {returnName } Public void SetName(String name) { This. name = name; } Public int Getage() {returnAge } Public void Setage(intAge) { This. Age = Age; }Private void writeobject(ObjectOutputStream out)throwsioexception{Out.writeobject (NewStringBuffer (name). reverse ()); Out.writeint (age); }Private void ReadObject(ObjectInputStream in)throwsClassNotFoundException, ioexception{ This. Name = ((StringBuffer) In.readobject ()). ToString (); This. Age = In.readint (); }@Override PublicStringtoString() {return "Name="+ This. Name +", age="+ This. Age; }}
WriteObject method, the name reversal after the write, ReadObject method directly read the inverted name can be. The demo class code does not change, the result
It can be seen from the results that custom serialization has been implemented, and that WriteObject and ReadObject have been called.
The attentive reader may find that the Personbean class int age uses the transient modifier, but the result after reading does not have an age equal to 0?? As I said earlier, the field decorated with the transient modifier is completely isolated. However, it is important to note that the serialization here is custom, and that the field is not processed during the customization process, but the transient modifier does not work here ...
There is also a more thorough serialization of the customization mechanism
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
The any-access-modifier in front of the method indicates that the method can be used for access rights such as private protected package-private, and its subclasses may obtain the method.
The following overrides the Personbean class, as follows:
Public class Personbean implements Serializable { PrivateString name;Private transient intAge PublicStringGetName() {returnName } Public void SetName(String name) { This. name = name; } Public int Getage() {returnAge } Public void Setage(intAge) { This. Age = Age; }Private void writeobject(ObjectOutputStream out)throwsioexception{Out.writeobject (NewStringBuffer (name). reverse ()); Out.writeint (age); }Private void ReadObject(ObjectInputStream in)throwsClassNotFoundException, ioexception{ This. Name = ((StringBuffer) In.readobject ()). ToString (); This. Age = In.readint (); }@Override PublicStringtoString() {return "Name="+ This. Name +", age="+ This. Age; }PrivateObjectWritereplace()throwsobjectstreamexception{arraylist<object> ArrayList =NewArraylist<> (); Arraylist.add ( This. name); Arraylist.add ( This. age);returnArrayList; }}
The serialization mechanism of Java guarantees that the Writereplace method of the object is called before the object is serialized, and if the method returns a Java object, the system becomes serialized to another Java object. The Personbean object is serialized in the above code, but the Writereplace method returns the ArrayList object, so the serialization holds the ArrayList object. The ArrayList object is also obtained when reading the saved serialized object, so the demo class code is changed to the following:
Public classObjectdemo { Public Static void Main(string[] args) {Personbean PersonBean1 =NewPersonbean (); Personbean1.setname ("Long"); Personbean1.setage ( -); Personbean personBean2 =NewPersonbean (); Personbean2.setname ("Fei"); Personbean2.setage ( -); ObjectOutputStream ObjectOutputStream =NULL; ObjectInputStream ObjectInputStream =NULL; String Path ="D:\\Program Files (x86) \\ADT\\workspace\\JavaIO\\demoTest.txt";Try{FileOutputStream FileOutputStream =NewFileOutputStream (path); FileInputStream FileInputStream =NewFileInputStream (path); ObjectOutputStream =NewObjectOutputStream (FileOutputStream); Objectoutputstream.writeobject (PERSONBEAN1); Objectoutputstream.writeobject (PERSONBEAN2); ObjectInputStream =NewObjectInputStream (FileInputStream);//Personbean personBean3 = (Personbean) objectinputstream.readobject ();//Personbean PersonBean4 = (Personbean) objectinputstream.readobject ();Arraylist<object> personBean3 = (arraylist<object>) objectinputstream.readobject (); Arraylist<object> PersonBean4 = (arraylist<object>) objectinputstream.readobject (); System. out. println (Personbean3.tostring ()); System. out. println (Personbean4.tostring ()); }Catch(IOException | ClassNotFoundException e) {e.printstacktrace (); }finally{if(ObjectOutputStream! =NULL) {Try{Objectoutputstream.close (); }Catch(IOException e) {E.printstacktrace (); } } } }}
Results:
- Five
The opposite of the Writereplace method is
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
This method can implement a protective copy of the entire object. This method is especially useful when serializing a singleton class and enumerating classes. Let's think about why??
The reason is that the Singleton class and the enumeration class want to return the original object after deserialization, but in the case of the method is not practical, the deserialization is put back to the original object of the clone!! Not the original Object! This method can solve this problem and return the same object that was originally serialized!! is not very strong!
- Six
Another mechanism for implementing custom serialization is to use the Externalizable interface, which requires two methods to implement the interface
void Readexternal (ObjectInput in)
void Writeexternal (ObjectOutput out)
These two methods and signatures are very similar using the ReadObject WriteObject method, except that the Externalizable interface enforces the use of custom serialization! In addition to rewriting these two methods, the other operations are the same, and it does not give an example:
-
Seven
Some points to note about the serialization mechanism:
1, the class name of the object, the field will be serialized, the method, the static field, the Transient field are not serialized
2, Implementing the Serializable interface using the transient modifier to decorate the field can not be serialized, although the static modifier can achieve the same effect, but the static transient cannot be mixed.
3, deserialization must have the class file of the serialized Object!!!
4. When a serialized object is read through a file or network, it must be read in the order in which it was actually written.
Eight
The Java serialization mechanism allows you to provide a private static final Serialversionuid value for the serialization class that identifies the serialized version of the class. If a class is upgraded, the serialization mechanism will treat them as a serialized version as long as its Serialversionuid field value remains the same.
In order to ensure the compatibility of serialized versions when deserializing, it is best to include the private static final long serialversionuid field in each class to be serialized, and its specific values can be defined by itself.
One disadvantage of not explicitly specifying the Serialversionuir field value is that the Serialversionuid value has a JVM that is computed based on the information about the class, and the modified class evaluates to a different result than the class before the modification. This causes the object's deserialization to fail because of the incompatibility of the class version.
Another disadvantage is that it is not good for programs to migrate between unused JVMs. Because different compilers calculate the value of the calculation strategy may be different, resulting in although the exhaustion has not changed, but because the JVM is different, the serialization version is incompatible and can not be correctly deserialized phenomenon.
There are such concentrations that need to be discussed:
1. If you modify a class to modify only the method, deserialization is not affected. No need to specify SERIALVERSIONUID value
2, if you modify the class only static field or transient field is modified, then deserialization is not affected. You do not need to specify a Serialversionuid value.
3. Modifying a non-static field non-transient field when modifying a class may cause the serialization version to be incompatible. If the object in the object flow and the new class contain field with the same name, and the type is different, the deserialization fails, and the class definition should update the SERIALVERSIONUID value. If the object stream contains more field than the new class, the extra field value is ignored, the serialized version is compatible, and the class definition can not update the SERIALVERSIONUID value. If the object in the new analogy object flow contains more field, the serialized version can also be compatible without specifying the SERIALVERSIONUID value, but the extra field value in the object that deserializes the resulting new class is null or 0.
SOURCE download
Java object Serialization in detail and example implementation and source download