Serialization and desequence
First, let’s learn about serialization and deserialization.
Serialization
Since objects existing in memory are temporary and cannot be stored for a long time, in order to maintain the state of the object, the object needs to be written to disk or other media. This process is called serialization.
Deserialization
Deserialization is precisely the reverse operation of serialization, that is, deserialize (read) objects that already exist on disk or other media into memory for subsequent operations, and this process is called deserialization.
Serialization is a process of storing the state of an object instance to a storage medium (disk or other media). In this process, the public and private fields of the object and the name of the class (including the assembly where the class resides) are first converted into a byte stream, and then the byte stream is written to the data stream. When the object is subsequently deserialized, a copy is created that is exactly the same as the original object.
Necessary conditions for implementing serialization
To implement serialization operations for an object, the class must implement the Serializable interface or Parcelable interface. The Serializable interface is a serialized abstract class in Java, and the Parcelable interface is a unique serialization interface in Android. In some cases, the serialization of the Parcelable interface is more efficient. We will analyze their implementation cases later. Here, as long as you clearly know that one of the Serializable interface or Parcelable interface must be implemented when implementing serialization operations.
Serialization application scenario
The following situations are mainly the following situations (but not limited to the following situations)
1) Write objects in memory to the hard disk;
2) Use sockets to transmit objects on the network;
3) Transfer objects through RMI (Remote Method Invoke remote method call);
What is the use of Serializable and what is the difference?
Parcelable and Serializable are two interfaces, and their function is to enable objects of classes that implement one of the interfaces to be serialized and deserialized.
(1) Serializable is a serialization interface provided by java. It is an empty interface that only identifies that this type can be serialized. The specific serialization/deserialization work is completed by ObjectInputStream(readObject)/ObjectOutputStream(writeObject). This process contains a large number of I/O operations and is relatively simple to use, but the impact of performance needs to be considered. Use scenario: Persist the object to the storage medium or transmit it over the network.
(2) The Parcelable interface is a serialized interface under the Android platform. Usually, the data passed across processes must be correctly implemented, such as Intent, Bitmap, etc. Parcelable is more complex than Serializable, but has better performance. Usage scenario: Implement serialization in memory, such as cross-process delivery. If a field does not need to be serialized, just ignore this field in the implement writeToParcel method.
2. Customize a class to implement Parcelable. What is the general process?
(1) First implement the Parcelable interface and implement the methods in the interface.
/** * Returns the content description of the current object, if there is a file descriptor, return 1, otherwise return 0. */ @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { (userId); (userName); (isMan ? 1 : 0); }
(2) Then create a member of the interface type Creator inside a Parcelable interface, and a construction method with a Parcel parameter is needed.
protected User(Parcel in) { userId = (); userName = (); isMan = () != 0; } /** * In aidl, when parameters are modified using in or inout, the server's onTransact() will call the CREATOR method to deserialize the parameters passed by the client. */ public static final Creator<User> CREATOR = new Creator<User>() { @Override public User createFromParcel(Parcel in) { return new User(in); } @Override public User[] newArray(int size) { return new User[size]; } };
(3) If you use out or inout directed tags to modify parameters in the aidl file, you must also implement a readFromParcel(Parcel) method. This is because using these two directed tags to modify parameters, after the server onTransact() returns, the client will call readFromParcel() to read (deserialize) the data in _reply. This method corresponds to writeToParcel, and is implemented as follows:
public void readFromParcel(Parcel in) { userId = (); userName = (); isMan = () == 1 ? true : false; }
3. Implement the Serializable interface
Implementing serialization by implementing the Serializable interface is relatively simple. You only need to implement this interface and specify serialVersionUID. Of course, this ID is optional and can be specified without manual specification. Serialize and deserialize via ObjectIntputStream /ObjectOutputStream.
ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream(new File("sdcard/"))); User user = new User(111, "Jdqm", true); (user); } catch (IOException e) { (); } finally { try { (); } catch (IOException e) { (); } }
ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream(new File("sdcard/"))); User user = (User) (); (TAG, "user: " + user); } catch (IOException | ClassNotFoundException e) { (); } finally { try { (); } catch (IOException e) { (); } }
Output result
User{userId=111, userName='Jdqm', isMan=true}
The meaning of serialVersionUID: assists in serialization and deserialization. When a class implements the SerSerializable interface and does not add the function field of serialVersionUID, the IDE will issue a warning. This field can be manually specified as a value, such as 1L, or it can be specified as IED to generate a long value according to the structure of the class. Their effects are the same. This value will be written to the storage medium during serialization. During deserialization, it will verify whether the serialVersionUID of the local class and the serialization medium are consistent. If the inconsistency is not the same, an exception will be thrown.
(1) If not specified: the system will calculate a serialVersionUID based on the class structure. Once the class structure changes, this value will change, which will cause deserialization failure;
(2) Specify a value: When the structure of the class changes, the value of serialVersionUID can also be not modified. In this case, the data can be replied to by deserializing to the greatest extent. If the structure of the class changes devastatingly, for example, the field data type changes, it will also lead to the desequence failure.
Note: Changes in the structure of a class refer to changes in the class member variables. Adding a normal method will not cause the calculated serialVersionUID to change. Changes to constructor methods, toString(), getter/setter will cause serialVersionUID to change.
- The member variable modified by transient does not participate in serialization. When deserializing, the member is changed to the default value of the data type.
- Static members do not participate in serialization
- The process of deserializing a new object does not call the constructor
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.