Java序列化演算法透析
Serialization(序列化)是一種將物件以一連串的位元組描述的過程;反序列化deserialization是一種將這些位元組重建成一個物件的過程。 Java序列化API提供一個處理物件序列化的標準機制。在這裡你能學到如何序列化一個對象,什麼時候需要序列化以及Java序列化的演算法,我們用一個實例來示範序列化以後的字節是如何描述一個對象的信息的。
序列化的必要性
Java中,一切都是對象,在分散式環境中經常需要將Object從這一端網路或設備傳遞到另一端。這就需要有一種可以在兩端傳輸資料的協定。 Java序列化機制就是為了解決這個問題而產生。
如何序列化一個物件
一個物件能夠序列化的前提是實作Serializable接口,Serializable介面沒有方法,更像是個標記。有了這個標記的Class就能被序列化機制處理。
100.
物件的序列化格式
將一個物件序列化後是什麼樣子呢?打開剛才我們將物件序列化輸出的temp.out文件,以16進位方式顯示。內容應該如下:
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64
public byte version = 100;
public byte count = 0;
而且都是byte型,理論上儲存這兩個域只需要2個byte,但是實際上temp.out佔據空間為51bytes,也就是說除了資料以外,還包括了對序列化物件的其他描述。
Java的序列化演算法
序列化演算法一般會依步驟做以下事情:
◆將物件實例相關的類別元資料輸出。
◆遞歸地輸出類別的超類別描述直到不再有超類別。
◆類元資料完了以後,開始從最頂層的超類別開始輸出物件實例的實際資料值。
◆從上到下遞迴輸出實例的數據
我們用另一個更完整涵蓋所有可能出現的情況的例子來說明:
class contain implements Serializable{
int containVersion = 11;
}
public class SerialTest extends parent implements Serializable {
int version = 66;
contain con = new contain();
public int getVersion() {
return version;
}
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("temp.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerialTest st = new SerialTest();
oos.writeObject(st);
oos.flush();
oos.close();
}
}
序列化後的格式如下:
AC ED 00 05 7372 00 0A 53 65 72 69 61 6C 54 65
73 74 05 52 81 5A AC 66 02 F6 02 00 0249 00 07
76 65 72 73 69 6F 6E4C00 03 63 6F 6E74 00 09
4C63 6F 6E 74 61 69 6E 3B 7872 00 06 70 61 72
65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 0149 00
0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70
0000000A 0000004273 72 00 07 63 6F 6E 74
61 69 6E FC BB E6 0E FB CB 60 C7 02 00 0149 00
0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78
700000000B
我們來仔細看看這些位元組都代表了啥。開頭部分,見顏色:
序列化演算法的第一步就是輸出物件相關類別的描述。例子所示物件為SerialTest類別實例,因此接下來輸出SerialTest類別的描述。參見顏色:
接下來,演算法輸出其中的一個域,intversion=66;見顏色:
然後,演算法輸出下一個域,contain con = new contain();這個有點特殊,是個物件。描述物件類型引用時需要使用JVM的標準物件簽章表示法,請參閱顏色:
.接下來演算法就會輸出超類別也就是Parent類別描述了,見顏色:
下一步,輸出parent類別的域描述,intparentVersion=100;同見顏色:
到此為止,演算法已經對所有的類別的描述都做了輸出。下一步就是把實例物件的實際值輸出了。這時候是從parent Class的域開始的,見顏色:
還有SerialTest類別的域:
再往後的bytes比較有意思,演算法需要描述contain類別的信息,要記住,現在還沒有對contain類別進行過描述,見顏色:
.輸出contain的唯一的域描述,intcontainVersion=11;
這時,序列化演算法會檢查contain是否有超類,如果有的話會接著輸出。
最後,將contain類別實際域值輸出。
OK,我們討論了java序列化的機制和原理,希望能對同學們有所幫助。