•序列化 ID 的問題
•靜態變數序列化
•父類的序列化與 Transient 關鍵字
•對敏感欄位加密
•序列化儲存規則
列表的每一部分講述了一個單獨的情境,讀者可以分別查看。
--------------------------------------------------------------------------------
回頁首
序列化 ID 問題
情境:兩個用戶端 A 和 B 試圖通過網路傳遞對象資料,A 端將對象 C 序列化為位元據再傳給 B,B 還原序列化得到 C。
問題:C 對象的全類路徑假設為 com.inout.Test,在 A 和 B 端都有這麼一個類檔案,功能代碼完全一致。也都實現了 Serializable 介面,但是還原序列化時總是提示不成功。
解決:虛擬機器是否允許還原序列化,不僅取決於類路徑和功能代碼是否一致,一個非常重要的一點是兩個類的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。清單 1 中,雖然兩個類的功能代碼完全一致,但是序列化 ID 不同,他們無法相互序列化和還原序列化。
清單 1. 相同功能代碼不同序列化 ID 的類對比
package com.inout;
import java.io.Serializable;
public class A implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
package com.inout;
import java.io.Serializable;
public class A implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
序列化 ID 在 Eclipse 下提供了兩種建置原則,一個是固定的 1L,一個是隨機產生一個不重複的 long 類型資料(實際上是使用 JDK 工具產生),在這裡有一個建議,如果沒有特殊需求,就是用預設的 1L 就可以,這樣可以確保代碼一致時還原序列化成功。那麼隨機產生的序列化 ID 有什麼作用呢,有些時候,通過改變序列化 ID 可以用來限制某些使用者的使用。
public static void main(String[] args) {
try {
//初始時staticVar為5
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
out.writeObject(new Test());
out.close();
//序列化後修改為10
Test.staticVar = 10;
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
Test t = (Test) oin.readObject();
oin.close();
public static void main(String[] args) {
try {
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
out.writeObject(new Test());
out.close();
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
Test test = new Test();
//試圖將對象兩次寫入檔案
out.writeObject(test);
out.flush();
System.out.println(new File("result.obj").length());
out.writeObject(test);
out.close();
System.out.println(new File("result.obj").length());
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
//從檔案依次讀出兩個檔案
Test t1 = (Test) oin.readObject();
Test t2 = (Test) oin.readObject();
oin.close();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("result.obj"));
Test test = new Test();
test.i = 1;
out.writeObject(test);
out.flush();
test.i = 2;
out.writeObject(test);
out.close();
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
"result.obj"));
Test t1 = (Test) oin.readObject();
Test t2 = (Test) oin.readObject();
System.out.println(t1.i);
System.out.println(t2.i);
清單 4 的目的是希望將 test 對象兩次儲存到 result.obj 檔案中,寫入一次以後修改對象屬性值再次儲存第二次,然後從 result.obj 中再依次讀出兩個對象,輸出這兩個對象的 i 屬性值。案例代碼的目的原本是希望一次性傳輸對象修改前後的狀態。