探討為什麼實現Serializable介面就可以序列化
在探討這個問題之前先上個概念。什麼是序列化和反序列化呢?
序列化就是指把Java物件轉換為位元組流寫入硬碟的過程。
public
static
void
writeObject
(
Object
obj
,
String
dstFilePath
)
throws
IOException
{
ObjectOutputStream
out
=
new
ObjectOutputStream
(
new
FileOutputStream
(
dstFilePath
));
out
。
writeObject
(
obj
);
out
。
close
();
}
反序列化就是指把硬碟上的二進位制檔案用位元組流讀入記憶體中,恢復為Java物件的過程
public static Object loadObject(String fromFile) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fromFile));
Object obj = in。readObject();
in。close();
return obj;
}
瞭解了序列化和反序列化後,該上菜了?
透過檢視原始碼我們可以看到
Serializable是一個空介面
,憑什麼你肚子裡啥都沒有,我實現了你,我就可以序列化了?難道是Serializable介面充錢了?很顯然這裡面肯定有文章。
我們進入ObjectOutputStream類中檢視writeObject(Object)方法進行檢視,至於為什麼要進這個類看,原因是序列化用到了這個方法。
看到了這個方法是不是看半天沒看出來啥,看不出來就對了鐵子,因為這裡做事的另有其人,它就是writeObject0()方法,那我們就應該進入這個方法一探究竟!
看到這相信大家都已經知道了,這裡做個簡單的說明:instanceof這個關鍵字呢是用來判斷是否是某種型別,那麼上圖就很好理解了。
JDK中的序列化和反序列化,在進行操作之前,會對型別做檢查。只有以下型別才能正常序列化:
String
Array
Enum
Serializable
所以我們自定義的型別要想實現序列化,必須實現Serializable介面,從而變成Serializable型別。
在這裡順便說個與本文章無關的卻被很多人忽視的知識。
serialVersionUID屬性
。在我們實現序列化介面以後,會有如下
警告
:提示我們沒有宣告一個long 型別的 static final 變數 serialVersionUID 。
The serializable class Student does not declare a static final serialVersionUID
field of type long
如果不顯式定義serialVersionUID,序列化時會根據當前類的結構自動生成一個序列號,這個序列化跟 類結構有關,如果類的結構有變化這個序列化也會變化。 基於上面的原因,如果我們的類在序列化以後,結構發生了變化(例如新增、刪除了屬性、方法),會 導致反序列化時類的序列號和當前序列化到硬碟上時的序列號不一致,從而無法正常反序列化(物件迷失在二進位制世界中回不來了)。
重點來了,實現序列化時在類名出現警告時,建議顯式定義一下UID。
上一篇:如何零基礎開始學日語
下一篇:又看《天道》-遙遠的救世主