1. Meaning:Save the state of an object (the quantity of attributes), and obtain it when appropriate.
2. programming requirements:Only class objects that implement the serializable interface can be serialized. The serializable interface does not define any members. It is only used to indicate that a class can be serialized.
3. serialization features:
(1) If a class can be serialized, its subclass can also be serialized.
(2) member data declared as static and transient cannot be serialized. Because static represents the state of the class, transient represents the temporary data of the object.
(3) related classes and interfaces: Provide the following classes and interfaces involved in Object serialization in the Java. Io package: objectoutput interface, objectoutputstream class, objectinput interface,
Objectinputstream class
4. objectoutput interface and objectoutputstream class
(1) objectoutput interface: It inherits the dataoutput interface and supports object serialization. The writeobject () method in it stores an object.
(2) objectoutputstream class: It inherits the outputstream class and implements the objectoutput interface. This class is used to implement Object Storage (call the writeobject () method in the objectoutput interface ).
Note:
(1) You can also use the objectoutputstream class object to write data values of other basic types.
(2) An ioexception is thrown when an error occurs.
5. objectinput interface and objectinputstream class
(1) objectinput interface: It inherits the datainput interface and supports object serialization. The readobject () method in it can read an object.
(2) objectinputstream class: It inherits the inputstream class and implements the objectinput interface. This class is used to implement Object Storage (call the readobject () method in the objectinput interface ).
Note:
(1) You can also use the objectinputstream class object to read data values of other basic types.
(2) An ioexception is thrown when an error occurs.
6. Object serialization purpose:
The serialization of objects is used to save the current working state of the application. It will be automatically restored to the previous state when the application is restarted next time or transmitted over the network. The following is a source code snippet for reading and writing object States (the complete program code will explain the object serialization technology in detail in our Java training course ):
Example:
(1) Save the object status
Fileoutputstream Fos = NULL;
Objectoutputstream OOS = NULL;
Frameconfig configdata = new frameconfig (this); // The frameconfig class contains the data to be saved.
Try
{
Fos = new fileoutputstream ("config. dat ");
Oos = new objectoutputstream (FOS );
Oos. writeobject (configdata );
Oos. Flush ();
FOS. Close ();
Oos. Close ();
}
Catch (ioexception E)
{
}
(2) read object status
Frameconfig configdata = NULL;
Currentdir = system. getproperty ("user. dir"); // obtain the current directory path of the program.
Try
{
Fileinputstream FCM = new fileinputstream ("config. dat ");
Objectinputstream OIS = new objectinputstream (FCM );
Configdata = (frameconfig) Ois. readobject ();
FCM. Close ();
Ois. Close ();
If (configdata! = NULL)
{// Get the data in the object and save it in the variable of the program
Currentdir = configdata. currentdir;
Windowstyle = configdata. windowstyle;
Topx = configdata. topx;
Topy = configdata. topy;
Required wwidth = configdata. Required wwidth;
Required wheight = configdata. Required wheight;
}
Else
{// If the data cannot be correctly read, the default value is used.
Topx = 0;
Topy = 0;
Required wwidth = toolkit. getdefaulttoolkit (). getscreensize (). width;
Required wheight = toolkit. getdefaulttoolkit (). getscreensize (). Height-25;
}
}
Catch (ioexception E)
{
}
Catch (classnotfoundexception E)
{
}
How to use Java serialization technology correctly --
Http://publishblog.blogchina.com/blog/tb. B? Diaryid = 279864
Abstract: This article comprehensively introduces all aspects of Java serialization technology, starting from the basics of serialization technology,
This article introduces the mechanism of Java serialization technology and the principle of serialization technology. The serialization
Advanced topic-how to precisely control serialization. By reading this article, you can learn how to use Java Sequences
To avoid misuse of the technology in actual programming. And Master how to use it efficiently
This technology is used to complete special functions.
Keywords: serialize, deserialize, classload, and Fingerprint Technology
(Fingerprint)
1 Java serialization technology Overview
Java serialization technology allows you to write the state of an object into a byte stream and
Read the data in the byte stream. Reconstructs an identical object. This mechanism allows you to pass objects through the network
And objects can be persisted to databases, files, and other systems at any time. The serialization mechanism of Java is RMI,
The technical basis of EJB, jnni, and other technologies.
1.1 serialization technology Basics
Not all Java classes can be serialized. To enable the serialization of the specified class, you must make the class
Implement the following interface:
Java. Io. serializable
Note that there are no methods for this interface. The implementation of this class is simply to mark the sequence supported by your class preparation
Features. Let's look at the following code:
/**
* Abstract basic classes and complete some basic definitions.
*/
Public abstract class humanoid
{
Protected int noofheads;
Private Static int totalheads;
Public humanoid ()
{
This (1 );
}
Public humanoid (INT noofheads)
{
How to correctly use Java serialization Technology Research Series
If (noofheads> 10)
Throw new error ("Be serious. More than 10 heads ?! ");
This. noofheads = noofheads;
Synchronized (humanoid. Class)
{
Totalheads ++ = noofheads;
}
}
Public int getheadcount ()
{
Return totalheads;
}
}
A subclass of this class is as follows:
/**
* Humanoid implementation class, implementing the serialization Interface
*/
Import java. Io .*;
Public class person extends humanoid
Implements java. Io. serializable
{
Private string lastname;
Private string firstname;
Private transient thread workerthread;
Private Static int population;
Public Person (string lastname, string firstname)
{
This. lastname = lastname;
This. firstname = firstname;
Synchronized (person. Class)
{
Population ++;
}
}
Public String tostring ()
{
Return "person" + firstname + "" + lastname;
}
Static synchronized public int getpopulation ()
{
Return population;
}
}
1.2 Object serialization and deserialization
The person class above implements the serializable interface, so it can be serialized. If we want
The following classes are required for serializing objects to files or databases:
Java. Io. objectoutputstream
How to correctly use Java serialization Technology Research Series
The following code completes the serialization of the person class:
/**
* Serialization class of person, which writes person into the file system.
*/
Import java. Io .*;
Public class writeinstance
{
Public static void main (string [] ARGs) throws exception
{
If (ARGs. length! = 1)
{
System. Out. println ("Usage: Java writeinstance file ");
System. Exit (-1 );
}
Fileoutputstream Fos = new fileoutputstream (ARGs [0]);
Objectoutputstream OOS = new objectoutputstream (FOS );
Person P = new person ("gaoyanbing", "haiger ");
Oos. writeobject (P );
}
}
If the class to be serialized cannot be serialized, the following exception will be thrown during serialization:
Java. Io. notserializableexception
After we serialize a person object to a file, if we need to restore the person object from the file,
We need to use the following classes:
Java. Io. objectinputstream
Implement the person class deserialization code in the file as follows:
/**
* Person deserialization class, which reads serialized data from the file system and constructs
* Person object.
*/
Import java. Io .*;
Public class readinstance
{
Public static void main (string [] ARGs) throws exception
{
If (ARGs. length! = 1)
{
System. Out. println ("Usage: Java readinstance FILENAME ");
System. Exit (-1 );
}
Fileinputstream FCM = new fileinputstream (ARGs [0]);
Objectinputstream OIS = new objectinputstream (FCM );
Object o = Ois. readobject ();
How to correctly use Java serialization Technology Research Series
System. Out. println ("read object" + O );
}
}
1.3 serialization-to-class processing principles
Not all fields and attributes of a class that implements the serialization interface can be serialized. We are divided into the following
Several sections are described as follows:
U if the class has a parent class, you can consider it in two cases if the parent class has implemented the serializable interface. Then
The corresponding fields and attributes of the parent class are processed in the same way as those of the class. If the parent class of this class is not implemented, it can be serialized.
All the field attributes of the parent class of this class will not be serialized.
U if a property of this class is identified as static, the property cannot be serialized because it does not belong to the state of the object;
U if a property of this class is identified by the transient keyword, the property cannot be serialized because it is only in a temporary state;
Note that when we mark a class that can be serialized, the following attributes should be set to transient to avoid serialization:
U thread-related attributes;
U needs to access attributes such as Io, local resources, and network resources;
U does not implement the property of the serializable interface; (Note: if an attribute is not serializable
If the object is not identified by the transient
Java. Io. notserializableexception ).
1.4 constructor and serialization
For processing a parent class, if the parent class does not implement a serialization interface, it must have a default constructor (that is, no
Parameter constructor ). Why do we need such a rule? Let's look at the actual example. Still use the above humanoid
And person class. We add the output statement to the constructor:
/**
* Abstract basic classes and complete some basic definitions.
*/
Public abstract class humanoid
{
Protected int noofheads;
Private Static int totalheads;
Public humanoid ()
{
This (1 );
System. Out. println ("human's default constructor is invoked ");
}
Public humanoid (INT noofheads)
{
If (noofheads> 10)
Throw new error ("Be serious. More than 10 heads ?! ");
How to correctly use Java serialization Technology Research Series
This. noofheads = noofheads;
Synchronized (humanoid. Class)
{
Totalheads ++ = noofheads;
}
}
Public int getheadcount ()
{
Return totalheads;
}
}
/**
* Humanoid implementation class, implementing the serialization Interface
*/
Import java. Io .*;
Public class person extends humanoid
Implements java. Io. serializable
{
Private string lastname;
Private string firstname;
Private transient thread workerthread;
Private Static int population;
Public Person (string lastname, string firstname)
{
This. lastname = lastname;
This. firstname = firstname;
Synchronized (person. Class)
{
Population ++;
}
System. Out. println ("Person's constructor is invoked ");
}
Public String tostring ()
{
Return "person" + firstname + "" + lastname;
}
Static synchronized public int getpopulation ()
{
Return population;
}
}
The result of running its serialization program and deserialization program on the command line is:
How to correctly use Java serialization Technology Research Series
As you can see, when reading data from the stream to construct the person object, the default humanoid of the parent class of the person
The constructor is called. Of course, you don't have to worry about this. If you don't give the parent class a default constructor, an error will be reported during running.
Here, we modify the humanoid of the parent class as follows:
/**
* Abstract basic classes and complete some basic definitions.
*/
Public class humanoid implements java. Io. serializable
{
Protected int noofheads;
Private Static int totalheads;
Public humanoid ()
{
This (1 );
System. Out. println ("human's default constructor is invoked ");
}
Public humanoid (INT noofheads)
{
If (noofheads> 10)
Throw new error ("Be serious. More than 10 heads ?! ");
This. noofheads = noofheads;
Synchronized (humanoid. Class)
{
Totalheads ++ = noofheads;
}
}
Public int getheadcount ()
{
Return totalheads;
}
}
We mark the parent class as serializable, and then let's look at the running results:
How to correctly use Java serialization Technology Research Series
We can see that during deserialization, if the parent class is also serializable, the default constructor will not
Call. Why?
This is because when Java deserializes A serialized object, it directly obtains its object data from the stream to generate
An object instance instead of its constructor. After all, our serializable classes may have multiple Constructor
Function. If our serializable class does not have a default constructor, The deserialization mechanism does not know which structure to call.
Function creation is correct.
1.5 serialization Problems
We can see that in the above example, In the person class, the population field is obviously intended to be tracked in
Number of instances of the person class in JVM. This field is assigned in its constructor.
During person serialization and deserialization, because the person constructor is not called during deserialization
This mechanism does not guarantee that the number of person instances in one JVM is correctly obtained. We will detail
Discuss this problem and provide a better solution.
2 control serialization Technology
2.1 use readobject and writeobject Methods
Because we use the following classes for Object serialization to implement the specific serialization process:
Java. Io. objectoutputstream
This class mainly implements the object serialization process through its writeobject method.
Mechanism to implement the User-Defined writeobject function. The method is to implement
How to correctly use Java serialization Technology Research Series
Writeobject method. This method automatically calls back the object when objectoutputstream serializes it.
To complete our custom serialization function.
Similarly, the deserialization class implements the same callback mechanism. We can extend its readobject to implement
Define the deserialization mechanism.
This flexible callback mechanism solves the problems brought about by the serialization mentioned above.
We can write the following readobject method to completely avoid the problem of Inaccurate population count:
Private void readobject (objectinputstream OIS)
Throws ioexception, classnotfoundexception
{
Ois. defaultreadobject ();
Synchronized (person. Class)
{
Population ++;
}
System. Out. println ("Adjusting population in readobject ");
}
2.2 class version control during serialization
This section discusses the following issues:
U how to find the class of the object during object deserialization;
How to control if the classes on both sides of serialization and deserialization are not of the same version;
2.2.1 serialization class searching mechanism
During object deserialization, classes that need to be deserialized must be found by classloader. Otherwise
Java. Lang. classnotfoundexception is thrown during deserialization. About classloader
For more information about searching for classes, see my another classloader article titled "in a non-management environment ".
How to achieve hot deployment. Here we only care about which classloader is assigned to the load
. To this end, we modify
/**
* Modified deserialization class
*/
Import java. Io .*;
Public class readinstance
{
Public void readperson (string filename)
{
How to correctly use Java serialization Technology Research Series
Try {
Fileinputstream FCM = new fileinputstream (filename );
Objectinputstream OIS = new objectinputstream (FCM );
Object o = Ois. readobject ();
System. Out. println ("read object" + O );
System. Out. println (this. getclass (). getclassloader ());
Person = (person) O;
System. Out. println (person. getclass (). getclassloader ());
} Catch (Java. Io. ioexception IE)
{
Ie. printstacktrace ();
} Catch (classnotfoundexception CE)
{
Ce. printstacktrace ();
}
}
Public static void main (string [] ARGs) throws exception
{
If (ARGs. length! = 1)
{
System. Out. println ("Usage: Java readinstance FILENAME ");
System. Exit (-1 );
}
Readinstance = new readinstance ();
Readinstance. readperson (ARGs [0]);
}
We mainly view the Class Loader through two lines of code with a yellow background. The running result is as follows:
It can be seen that the class loader of the serialization class officially implements its deserialization class. In this case, we
You can publish the latest version of the person class to be visible only to the classloader of the deserializer. Older
Is not visible to the classloader to avoid the problem of multiple versions of the class in the deserialization process. When
However, we need to make a special discussion on the version of the class below.
How to correctly use Java serialization Technology Research Series
2.2.2 serialization multi-Version Control
If there are versions of the class in different periods in the deserialization JVM, how is the deserialization mechanism located?
Why?
To avoid this problem, Java serialization provides a fingerprint technology. Different classes have different versions
Fingerprint information, through which you can identify whether the classes in the current JVM correspond to the objects to be deserialized
The class is of the same version. The fingerprint is implemented as a 64-bit long type. Using a secure hash algorithm (SHA-1)
The basic information of the serialized class (including the class name, the class editor, the class parent interface, and various attributes ).
The 64-bit fingerprint. We can use the built-in JDK command serialver to print the fingerprints of A serializable class.
Information. As follows:
When the classes on both sides are different, the deserialization will report an error:
How to correctly use Java serialization Technology Research Series
Solution: From the output above, we can see that the fingerprint is provided through the following internal variables:
Private Static final long serialversionuid;
If we provide control over this attribute in the class, we can implement custom control over the serialization fingerprint of the class. Is
Here, we define this variable in the person class:
Private Static final long serialversionuid = 692166139298733410000l;
When we modify the person class and release different versions to the deserialization JVM, there will be no version conflict.
. Note that the value of serialversionuid must be obtained through the serialver command. But not
You can set it as needed. Otherwise, it may overlap.
Note that setting serialversionuid manually may cause some problems. For example, we may
Key changes were made. The version of the classes on both sides produces substantial incompatibility. To avoid such failures, we need
The following table lists the changes that may cause substantial incompatibility and
Slightly (compatible) changes:
Example of changing the type
Compatible changes
U add attributes (adding fields)
U Add/delete classes (adding/removing classes)
U Add/delete writeobject/readobject method (adding/removing
Writeobject/readobject)
U Add a serialization flag (adding serializable)
U changing access modifier)
U Delete static/non-serializable attributes (removing static/transient from
A field)
Incompatible changes
U ing Fields)
U deletes a class (removing classes in
Hierarchy)
U add static/non-serializable fields (adding static/transient to
Field)
U modify the type of a simple variable (Changing Type of a primitive)
U switching between serializable or externalizable
Removing serializable/externalizable)
U changes the control of default attribute values in readobject/writeobject (changing
Whether readobject/writeobject handles default Field
Data)
U adding writereplace or readresolve that produces
Objects incompatible with older versions
In addition, the serialization specification of Java does not indicate the reverse order after we make substantial incompatibility changes to the class.
What are the consequences of column-based configuration. Not all incompatible modifications will cause deserialization failure. For example, if we delete
Except for one attribute, the deserialization mechanism simply discards the data of this attribute during deserialization. Slave
In the JDK reference, we can obtain the following table about the consequences of some incompatible modifications:
How to correctly use Java serialization Technology Research Series
Deserialization results caused by incompatible modifications
Delete attributes
(Deleting a field) silently ignored
Delete a class in an inheritance or implementation level
(Moving classes in inheritance
Hierarchy)
Exception
Add static/non-serializable attributes
(Adding static/transient)
Silently ignored
Modify basic property types
(Changing primitive type)
Exception
Change the use of default attribute values
(Changing use of default field data)
Exception
Switching between serialization and non-serialization and internal and external classes
(Switching serializable and
Externalizable)
Exception
Delete the serializable or externalizable flag
(Removing serializable or
Externalizable)
Exception
Returns incompatible classes.
(Returning incompatible class)
Depends on incompatibility
2.3 display control the serialization process of attributes
In the default Java serialization mechanism, the mappings between the object attributes and the attributes in the byte stream are all from
Dynamic and transparent. During serialization, the property name of the object is the name of the byte stream by default. When
During object deserialization, the object is mapped to the attributes of the newly generated object based on the name in the byte stream.
For example. When one of our person objects is serialized, The firstname attribute of person is
The default name of this attribute in the byte stream. When the person object is deserialized, the serialization mechanism Sets
The value of firstname obtained in the stream is assigned to the firstname attribute in the new person instance.
The serialization mechanism of Java provides related hook functions for our use. Through these hook functions, we can accurately
Control the above serialization and deserialization process. The internal class getfield of objectinputstream provides
Data is obtained from the stream, while the internal putfield class of objectoutputstream provides the attribute data
The control mechanism in the stream. For objectinputstream, we need to complete the process from the stream in the readobject method.
Read the corresponding attribute data. For example, we update the version of the person class from table 1 below to table 2:
/**
* For the person class of the old version before modification, we deleted all irrelevant codes for simplicity.
*/
Import java. Io .*;
Public class person extends humanoid
Implements java. Io. serializable
{
Private string lastname;
How to correctly use Java serialization Technology Research Series
Private string firstname;
Private Static final long serialversionuid = 692166139298733410000l;
Private person ()
{
}
Public Person (string lastname, string firstname)
{
This. lastname = lastname;
This. firstname = firstname;
}
Public String tostring ()
{
Return "person" + firstname + "" + lastname;
}
}
The modified person is:
/**
* The modified person class changes firstname and lastname to fullname.
*/
Import java. Io .*;
Public class person extends humanoid
Implements java. Io. serializable
{
Private string fullname;
Private Static final long serialversionuid = 692166139298733410000l;
Private person ()
{
}
Public Person (string fullname)
{
This. lastname = fullname;
}
Public String tostring ()
{
Return "person" + fullname;
}
}
To do this, we need to write the readobject method of the person class as follows:
Private void readobject (objectinputstream OIS)
Throws ioexception, classnotfoundexception
{
Objectinputstream. getfield gf = Ois. readfields ();
Fullname = (string) Gf. Get ("fullname", null );
If (fullname = NULL)
{
String lastname = (string) Gf. Get ("lastname", null );
How to correctly use Java serialization Technology Research Series
String firstname = (string) Gf. Get ("firstname", null );
If (lastname = NULL) | (firstname = NULL ))
{
Throw new invalidclassexception ("invalid person ");
}
Fullname = firstname + "" + lastname;
}
}
The execution sequence is:
1) Compile the old person and all classes;
2) serialize the old person to a file;
3) change to the person class of the new version;
4) Compile the new person class;
5) deserialization of person;
The execution result is very smooth. The modified deserialization mechanism still correctly obtains the old version of person from the stream.
Attribute Information and assign values to the attributes of the new version of person.
When using readobject of objectinputstream to process deserialization attributes, pay attention to the following two points:
Once you use the deserialization of the property under your control, you must complete the deserialization of all properties (that is,
Attribute assignment );
When using the get method of the internal getfield class, note that if get is an earlier version
This method throws an exception if the attribute appears in the new version:
Illegalargumentexception: no such field, so we should
To use this method.
Similarly, we can use the writeobject method to control the serialization process of object attributes. Here we will not try again
For example, if you are interested, you can implement the writeobject method of the person class and use
The internal class putfield of objectoutputstream is used to manually serialize attributes.
3. Conclusion
The Java serialization mechanism provides powerful processing capabilities. In general, in order to make full use of the automation provided by Java
Mechanism, we do not need to interfere with the serialization process. But in some cases, we need to implement some special
Functions, such as multi-Version Control of classes and serialization control of special fields. We can achieve this in multiple ways
Some features:
U uses the hook functions readobject and writeobject provided by the serialization mechanism;
U overwrites the metadata information of the serialization class;
How to correctly use Java serialization Technology Research Series
U enables the class to implement the externalizable interface instead of the serializable interface.
For more information about the externalizable interface, refer to the detailed documentation provided by the JDK help.
For quick reference to the introduction of Java I/O system in chapter 10 of thinking in Java.
References:
1. Sun's specification for Java virtual machines the Java Virtual Machine specification;
2. Thinking in Java;
3. Java platform-based componentized development technology.
About Author:
Gao yingbing (haiger or tuskrabbit) is the overall design of the business department of Shenzhen Huawei Technology Co., Ltd.
Department of Architecture designer, with multiple large-scale enterprise application systems (millions, tens of millions of users) architectural design experience. Personal research
Focus on the whole-process modeling technology, web engineering technology, and Enterprise Application Integration (EAI) on the J2EE platform.
Consultation and implementation. You can get in touch with him through the gaoyb@huawei.com.