In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail how to achieve serialization and deserialization in ava. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.
Meaning
Serialization: the object is written to the IO stream, and the implementation object becomes a file. Deserialization: the objects in the file are recovered and restored to memory to deserialize. Meaning: the greatest significance of serialization is that objects can be transferred across hosts, and these objects can be saved on disk and exist independently of the program.
Serialization needs to implement an interface
An object needs to be serialized, and here, you need to implement an interface, which is
Java.io.Serializable
Click on this interface and you can see that the definition is as follows
Public interface Serializable {
}
Serialize
To turn an Java object into an array, you need to use a stream to write a Java object to the byte stream. The code is as follows
Import java.io.*
Import java.util.Arrays
Public class Main {
Public static void main (String [] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream ()
Try (ObjectOutputStream output = new ObjectOutputStream (buffer)) {
/ / write int:
Output.writeInt (12345)
/ / write String:
Output.writeUTF ("Hello")
/ / write Object:
Output.writeObject (Double.valueOf (123.456))
}
System.out.println (Arrays.toString (buffer.toByteArray ()
}
}
Here, through the ObjectOutputStream type, the data is written into the buffer.
What is written here are the basic data types, which are int,boolean or String, because these basic data types implement a serialized interface, so the content of the write is very large.
Deserialization
ObjectInputStream is responsible for reading objects from a byte stream. The code is as follows
Try (ObjectInputStream input = new ObjectInputStream (...)) {
Int n = input.readInt ()
String s = input.readUTF ()
Double d = (Double) input.readObject ()
}
Here, to avoid the incompatibility of the Java class when it is not serialized. Because there is a class class on one host and no class class on the other, it needs to be deserialized. Also identify the version and use serialVersionUID to define a static version. Examples are as follows
Public class Person implements Serializable {
Private static final long serialVersionUID = 2709425275741743919L
}
Principle
Here we will explain the principle of Java serialization. The principle is a little boring, and the guest can skip it.
A piece of serialization code
Public class SerializeTest {
Public void serialize () throws Exception {
Data1 d = new data1 ()
D.setId (1036)
D.setName ("data1")
D.setPwd ("pwd1")
D.setPwd2 ("pwd2")
FileOutputStream fos = new FileOutputStream ("d:/project/serial/data1")
ObjectOutputStream oos = new ObjectOutputStream (fos); / / create Object output stream object
Oos.writeObject (d); / / write serialized data data1 class to the data1 file
Fos.close ()
Oos.close ()
System.out.println (serialization complete)
}
Public data1 deSerialize () throws Exception {
FileInputStream fis = new FileInputStream ("d:/project/serial/data1")
ObjectInputStream ois = new ObjectInputStream (fis); / / create Object input stream object
Data1 d = (data1) ois.readObject (); / / deserialize data1 class data from the data1 file
Ois.close ()
Fis.close ()
Return d
}
Public static void main (String [] args) throws Exception {
SerializeTest s = new SerializeTest ()
S.serialize ()
Data1 d = s.deSerialize ()
System.out.println ("id:" + d.getId ())
System.out.println ("name:" + d.getName ())
System.out.println ("pwd:" + d.getPwd ())
}
}
After serialization, this is what happens when you open it with notdpad++
View in hexadecimal
That is, these are serialization
Source code parsing
Serialization relies on ObjectOutputStream. Structural parameters
Public ObjectOutputStream (OutputStream out) throws IOException {
VerifySubclass ()
Bout = new BlockDataOutputStream (out)
Handles = new HandleTable (10, (float) 3.00)
Subs = new ReplaceTable (10, (float) 3.00)
EnableOverride = false
WriteStreamHeader ()
Bout.setBlockDataMode (true)
If (extendedDebugInfo) {
DebugInfoStack = new DebugTraceInfoStack ()
} else {
DebugInfoStack = null
}
}
The writeStreamHeader code is as follows
Protected void writeStreamHeader () throws IOException {
Bout.writeShort (STREAM_MAGIC)
Bout.writeShort (STREAM_VERSION)
}
WriteShort writes two bytes to the container, where 4 bytes are initialized (one STREAM_MAGIC, one STREAM_VERSION)
/ * *
* Magic number that is written to the stream header.
, /
Final static short STREAM_MAGIC = (short) 0xaced
/ * *
* Version number that is written to the stream header.
, /
Final static short STREAM_VERSION = 5
That is, ac ed 00 05, which declares the use of the serialization protocol and describes the serialized version
Start serializing writeObject ()
Public final void writeObject (Object obj) throws IOException {
If (enableOverride) {
WriteObjectOverride (obj)
Return
}
Try {
WriteObject0 (obj, false)
} catch (IOException ex) {
If (depth = = 0) {
WriteFatalException (ex)
}
Throw ex
}
}
WriteObject0 () is usually called directly.
Private void writeObject0 (Object obj, boolean unshared)
Throws IOException
{
Boolean oldMode = bout.setBlockDataMode (false)
Depth++
Try {
/ / handle previously written and non-replaceable objects
Int h
... Omit the code
If (obj instanceof ObjectStreamClass) {
WriteClassDesc ((ObjectStreamClass) obj, unshared)
Return
}
/ / check for replacement object
Object orig = obj
Class cl = obj.getClass ()
ObjectStreamClass desc
For (;;) {
/ / REMIND: skip this check for strings/arrays?
Class repCl
Desc = ObjectStreamClass.lookup (cl, true)
If (! desc.hasWriteReplaceMethod ()) | |
(obj = desc.invokeWriteReplace (obj)) = = null | |
(repCl = obj.getClass ()) = = cl)
{
Break
}
Cl = repCl
}
/ / remaining cases
If (obj instanceof String) {
WriteString ((String) obj, unshared)
} else if (cl.isArray ()) {
WriteArray (obj, desc, unshared)
} else if (obj instanceof Enum) {
WriteEnum ((Enum) obj, desc, unshared)
} else if (obj instanceof Serializable) {
WriteOrdinaryObject (obj, desc, unshared)
} else {
If (extendedDebugInfo) {
Throw new NotSerializableException (
Cl.getName () + "n" + debugInfoStack.toString ()
} else {
Throw new NotSerializableException (cl.getName ())
}
}
} finally {
Depth--
Bout.setBlockDataMode (oldMode)
}
}
For those later judgments, it is easy to see that serialized data is written in different ways depending on the type of object. Here, if the object implements the Serializable interface, the writeOrdinaryObject () method is called.
Then it turns out that this method also passes in a desc, which is the ObjectStreamClass class created in a for (;;) loop before this function to describe the object class information.
Then watch writeOrdinaryObject ()
Private void writeOrdinaryObject (Object obj
ObjectStreamClass desc
Boolean unshared)
Throws IOException
{
If (extendedDebugInfo) {
DebugInfoStack.push (
(depth = = 1? "root": ") +" object (class "" +)
Obj.getClass () .getName () + "," + obj.toString () + ")
}
Try {
Desc.checkSerialize ()
Bout.writeByte (TC_OBJECT)
WriteClassDesc (desc, false)
Handles.assign (unshared? Null: obj)
If (desc.isExternalizable () & &! desc.isProxy ()) {
WriteExternalData ((Externalizable) obj)
} else {
WriteSerialData (obj, desc)
}
} finally {
If (extendedDebugInfo) {
DebugInfoStack.pop ()
}
}
}
First, writeByte (), write a byte of TC_OBJECT flag bit (hexadecimal 73), and then call writeClassDesc (desc) to write this kind of information generated before, follow up to see writeClassDesc ()
Private void writeClassDesc (ObjectStreamClass desc, boolean unshared)
Throws IOException
{
Int handle
If (desc = = null) {
WriteNull ()
} else if (! unshared & & (handle = handles.lookup (desc))! =-1) {
WriteHandle (handle)
} else if (desc.isProxy ()) {
WriteProxyDesc (desc, unshared)
} else {
WriteNonProxyDesc (desc, unshared)
}
}
IsProxy () determines whether the class is a dynamic proxy class, and has no knowledge of dynamic proxy (first mark). Here, because it is not a dynamic proxy class, it will call the
WriteNonProxyDesc (desc)
Follow up writeNonProxyDesc (desc)
Private void writeNonProxyDesc (ObjectStreamClass desc, boolean unshared)
Throws IOException
{
Bout.writeByte (TC_CLASSDESC)
Handles.assign (unshared? Null: desc)
If (protocol = = PROTOCOL_VERSION_1) {
/ / do not invoke class descriptor write hook with old protocol
Desc.writeNonProxy (this)
} else {
WriteClassDescriptor (desc)
}
Class cl = desc.forClass ()
Bout.setBlockDataMode (true)
If (cl! = null & & isCustomSubclass ()) {
ReflectUtil.checkPackageAccess (cl)
}
AnnotateClass (cl)
Bout.setBlockDataMode (false)
Bout.writeByte (TC_ENDBLOCKDATA)
WriteClassDesc (desc.getSuperDesc (), false)
}
Found that writeByte wrote a byte of TC_CLASSDESC (hexadecimal 72)
Then the next judgment is that true enters writeNonProxy ()
WriteNonProxy ()
Void writeNonProxy (ObjectOutputStream out) throws IOException {
Out.writeUTF (name)
Out.writeLong (getSerialVersionUID ())
Byte flags = 0
If (externalizable) {
Flags | = ObjectStreamConstants.SC_EXTERNALIZABLE
Int protocol = out.getProtocolVersion ()
If (protocol! = ObjectStreamConstants.PROTOCOL_VERSION_1) {
Flags | = ObjectStreamConstants.SC_BLOCK_DATA
}
} else if (serializable) {
Flags | = ObjectStreamConstants.SC_SERIALIZABLE
}
If (hasWriteObjectData) {
Flags | = ObjectStreamConstants.SC_WRITE_METHOD
}
If (isEnum) {
Flags | = ObjectStreamConstants.SC_ENUM
}
Out.writeByte (flags)
Out.writeShort (fields.length)
For (int I = 0; I < fields.length; iTunes +) {
ObjectStreamField f = fields [I]
Out.writeByte (f.getTypeCode ())
Out.writeUTF (f.getName ())
If (! f.isPrimitive ()) {
Out.writeTypeString (f.getTypeString ())
}
}
}
Calling writeUTF () writes the class name, the writeUTF () function, which writes a two-byte class name length before writing the hexadecimal class name.
Then call writeLong to write the serialized UID
Then there is a judgment that determines how the class interface is implemented, calling writeByte () to write a byte of flag bit.
Here are all the markers
/ * *
* Bit mask for ObjectStreamClass flag. Indicates Externalizable data
* written in Block Data mode.
* Added for PROTOCOL_VERSION_2.
*
* @ see # PROTOCOL_VERSION_2
* @ since 1.2
, /
Final static byte SC_BLOCK_DATA = 0x08
/ * *
* Bit mask for ObjectStreamClass flag. Indicates class is Serializable.
, /
Final static byte SC_SERIALIZABLE = 0x02
/ * *
* Bit mask for ObjectStreamClass flag. Indicates class is Externalizable.
, /
Final static byte SC_EXTERNALIZABLE = 0x04
/ * *
* Bit mask for ObjectStreamClass flag. Indicates class is an enum type.
* @ since 1.5
, /
Final static byte SC_ENUM = 0x10
Then call writeShort to write the field length of two bytes (for example, if there are three variables, write 0003)
Then there is a loop, ready to write the variable name of the class and its corresponding variable type
Each cycle:
WriteByte writes a byte variable type; writeUTF () writes the variable name to determine whether it is the original type, that is, if the object is not the original type (basic type), then call writeTypeString ()
This writeTypeString (), if it is a string, calls writeString ().
And this writeString () is often written like this, if the length of the string (not the size) is less than two bytes, first write a byte of TC_STRING (hexadecimal 74), then call writeUTF (), write a signature, which seems to be related to jvm, and finally write something like the following string
74 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b
The "translation" means that the string type is 18 bytes long, and the variable name is
Ljava/lang/string
And if we say that the above object has been declared before, that is, there is this string 74 00 12. 3b in front of it.
Then I will call writeHandle (), first write a byte of TC_REFERENCE (hexadecimal 71), and then call writeInt () to write 007e0000 + handle. This handle is the previously declared position of the object. Here, I haven't cleared up how the location is located, which is generally 0001, that is, writeHandle (), which is generally written as follows:
71 00 7e 00 XX such 5 bytes (the last 00 XX is not sure, I'll figure it out later, it's usually 00 01)
The above is over, that is, we have finished writing writeNonProxy (), and now we go back to writeNonProxyDesc () again.
Next, continue to call writeByte () to write a byte of TC_ENDBLOCKDATA (hexadecimal 78), the block end flag bit.
Then call writeCLassDesc (), and the parameter is the parent class of desc. If the parent class does not implement the serialization interface, it will not be written. Otherwise, go back to the step of writeNonProxyDesc and start writing the class information and variable information of the parent class (start bit 72, stop bit 78), which is similar to a recursive call. Finally, if the parent class of the serialization interface is not implemented, writeNull () will be called to write a byte of TC_NULL (hexadecimal 70). It means you don't have a date.
All right, anyway, after the recursive call of writeClassDesc () is finished, we go back to writeOrdinaryObject ().
Next, call writeSerialData (), ready to write serialized data
WriteSerialData ()
Private void writeSerialData (Object obj, ObjectStreamClass desc)
Throws IOException
{
ObjectStreamClass.ClassDataSlot [] slots = desc.getClassDataLayout ()
For (int I = 0; I < slots.length; iTunes +) {
ObjectStreamClass slotDesc = slotts [I] .desc
If (slotDesc.hasWriteObjectMethod ()) {
PutFieldImpl oldPut = curPut
CurPut = null
SerialCallbackContext oldContext = curContext
If (extendedDebugInfo) {
DebugInfoStack.push (
"custom writeObject data (class" +)
SlotDesc.getName () + ""))
}
Try {
CurContext = new SerialCallbackContext (obj, slotDesc)
Bout.setBlockDataMode (true)
SlotDesc.invokeWriteObject (obj, this)
Bout.setBlockDataMode (false)
Bout.writeByte (TC_ENDBLOCKDATA)
} finally {
CurContext.setUsed ()
CurContext = oldContext
If (extendedDebugInfo) {
DebugInfoStack.pop ()
}
}
CurPut = oldPut
} else {
DefaultWriteFields (obj, slotDesc)
}
}
}
A loop with an upper limit on the number of classes (including parent classes)
Each round:
Call defaultWriteFields ()
DefaultWriteFields ()
Private void defaultWriteFields (Object obj, ObjectStreamClass desc)
Throws IOException
{
Class cl = desc.forClass ()
If (cl! = null & & obj! = null & &! cl.isInstance (obj)) {
Throw new ClassCastException ()
}
Desc.checkDefaultSerialize ()
Int primDataSize = desc.getPrimDataSize ()
If (primVals = = null | | primVals.length < primDataSize) {
PrimVals = new byte [primDataSize]
}
Desc.getPrimFieldValues (obj, primVals)
Bout.write (primVals, 0, primDataSize, false)
ObjectStreamField [] fields = desc.getFields (false)
Object [] objVals = new Object [desc.getNumObjFields ()]
Int numPrimFields = fields.length-objVals.length
Desc.getObjFieldValues (obj, objVals)
For (int I = 0; I < objVals.length; iTunes +) {
If (extendedDebugInfo) {
DebugInfoStack.push (
"field (class"+ desc.getName () +", name:"+
Fields [numPrimFields + I] .getName () + ", type:"+
Fields [numPrimFields + I] .getType () + ")")
}
Try {
WriteObject0 (objVals [I]
Fields [numPrimFields + I] .isUnshared ()
} finally {
If (extendedDebugInfo) {
DebugInfoStack.pop ()
}
}
}
}
First determine whether it is a basic type, and if so, call write to write serialized data directly.
Otherwise, get the number of all variables in the class and start the loop
Each round of this cycle:
Call writeObject0 () to write the variable, that is, according to the variable type, with the appropriate method.
The final cycle ends.
With all the variables written, the first loop ends, the call to the writeSerialData () method finishes, it goes back to writeOrdinaryObject (), the execution ends back to writeObject0 (), and back to writeObject ().
On how to achieve serialization and deserialization in ava to share here, I hope that the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.