- 序列化帶來的直接開銷很是低,可是長期開銷是實實在在的
實現 Serializable 接口最大的代價就是java
- 一旦一個類發佈,大大下降了改變其實現的靈活性
- 由於此時,它的字節流編碼就變成了其導出API的一部分
- 若是不設計一種自定義序列化形式,僅僅使用默認序列化,
- 那麼私有和包級私有實例,都變成導出api的一部分
- 不符合最低限度訪問域的準則
- 默認序列化可能出現新老版本序列化和反序列化不兼容
- 仔細設計一種高質量的序列化形式,長期使用,初始付出的成本是值得的
- 序列化會使得類的演變受到限制
實現 Serializable 第二個代價:api
- 增長了出現 BUG、安全漏洞的可能性
- 對象是構造器建立的
- 序列化機制是語言以外的對象建立機制
- 反序列化機制都是一個隱藏的構造器
- 默認序列化機制的反序列化過程的約束關係很容易遭到破壞、非法訪問
第三個代價:緩存
- 隨着類發行新的版本、相關測試負擔也增長了
- 一個可序列化的類被修訂後,要檢查,在新版本序列化一個類,在老版本是否能夠反序列化,反之亦然
- 測試工做量乘積增加
實現Serializable 確實帶來了益處:安全
- 好比一些值類:Date、BigInteger 能夠實現Serializable
- 活動實體類:Thread pool 通常不實現Serializable
爲了繼承而設計的類、接口,儘量少的實現 Serializable 接口框架
- 可是若是專門設計參與到某個框架的類,該框架要求必須實現Serializable 時例外
- 爲了繼承而設計的類,實現了Serializable 接口的有
- Throwable類:RMI異常,能夠從服務端傳到客戶端
- Component :GUI 能夠被髮送保存和恢復
- HttpServlet抽象類:會話狀態能夠被緩存
- 若是實現帶有實例域的類,實例域被初始化成默認值會違背約束條件
- 就必須添加下文中的方法
若是一個專門爲了繼承而設計的類不是可序列化的,測試
- 就不可能編寫出可序列化的子類。
- 特別是,若是超類沒有提供可訪問的無參構造器,子類也不可能作到可序列化。
- 所以,對於爲繼承而設計的不可序列化的類,你應該考慮提供一個無參構造器。
內部類不該該實現Serializable。編碼
- 它們使用編譯器產生的合成域來保存指向外圍實例的引用,
- 以及保存來自外圍做用域的局部變量的值。
- 所以,內部類的默認序列化形式是定義不清楚的。
- 然而,靜態成員類倒是能夠實現Serializable接口。
千萬不要認爲實現Serializable接口會很容易。設計
- 除非一個類在用了一段時間以後就會被拋棄,
- 不然,實現Serializable接口就是個很嚴肅的承諾,必須認真對待。
- 若是一個類是爲了繼承而設計的,則更加須要加倍當心。
- 對於這樣的類而言,在「容許子類實現Serializable接口」或「禁止子類實現Serializable接口」二者之間的一個折衷設計方案是,
- 提供一個可訪問的無參構造器,這種設計方案容許(但不要求)子類實現Serializable接口。
- 至於爲何須要父類有一個無參的構造器,
- 是由於子類先序列化自身的時候先調用父類的無參的構造器。
- 實例:
-
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
out.defaultWriteObject();//先序列化對象
out.writeInt(parentvalue);//再序列化父類的域
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException{
in.defaultReadObject();//先反序列化對象
parentvalue=in.readInt();//再反序列化父類的域
}