日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java serializable深入了解

發布時間:2025/3/14 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java serializable深入了解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

聲明:本文轉自csdn論壇,原文地址為http://blog.csdn.net/zdw890412/article/details/7380069,對原作者表示感謝!

引言

將?Java?對象序列化為二進制文件的 Java?序列化技術是?Java?系列技術中一個較為重要技術點,在大部分情況下,開發人員只需要了解被序列化類需要實現 Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 進行對象讀寫。然而在有些情況下,光知道這些還遠遠不夠,文章列舉了筆者遇到一些真實情境,它們與?Java?序列化相關,通過分析情境出現原因,使讀者輕松牢記?Java?序列化中一些高級認識。

本文將逐一介紹幾個情境,順序如下面列表。

?序列化?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 可以用來限制某些用戶的使用。

特性使用案例

讀者應該聽過 Fa?ade 模式,它是為應用程序提供統一的訪問接口,案例程序中的 Client 客戶端使用了該模式,案例程序結構圖如圖 1 所示。

Client 端通過 Fa?ade Object 才可以與業務邏輯對象進行交互。而客戶端的 Fa?ade Object 不能直接由 Client 生成,而是需要 Server 端生成,然后序列化后通過網絡將二進制對象數據傳給 Client,Client 負責反序列化得到 Fa?ade 對象。該模式可以使得 Client 端程序的使用需要服務器端的許可,同時 Client 端和服務器端的 Fa?ade Object 類需要保持一致。當服務器端想要進行版本更新時,只要將服務器端的 Fa?ade Object 類的序列化 ID 再次生成,當 Client 端反序列化 Fa?ade Object 就會失敗,也就是強制 Client 端從服務器端獲取最新程序。

靜態變量序列化

情境:查看清單 2 的代碼。

public class Test implements Serializable {private static final long serialVersionUID = 1L;public static int staticVar = 5;public static void main(String[] args) {try {//初始時staticVar為5ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("result.obj"));out.writeObject(new Test());out.close();//序列化后修改為10Test.staticVar = 10;ObjectInputStream oin = new ObjectInputStream(new FileInputStream("result.obj"));Test t = (Test) oin.readObject();oin.close();//再讀取,通過t.staticVar打印新的值 System.out.println(t.staticVar);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}} }

清單 2 中的 main 方法,將對象序列化后,修改靜態變量的數值,再將序列化對象讀取出來,然后通過讀取出來的對象獲得靜態變量的數值并打印出來。依照清單 2,這個 System.out.println(t.staticVar) 語句輸出的是 10 還是 5 呢?

最后的輸出是 10,對于無法理解的讀者認為,打印的 staticVar 是從讀取的對象里獲得的,應該是保存時的狀態才對。之所以打印 10 的原因在于序列化時,并不保存靜態變量,這其實比較容易理解,序列化保存的是對象的狀態,靜態變量屬于類的狀態,因此?序列化并不保存靜態變量

父類的序列化與 Transient 關鍵字

情境:一個子類實現了 Serializable 接口,它的父類都沒有實現 Serializable 接口,序列化該子類對象,然后反序列化后輸出父類定義的某變量的數值,該變量數值與序列化時的數值不同。

解決要想將父類對象也序列化,就需要讓父類也實現Serializable 接口。如果父類不實現的話的,就?需要有默認的無參的構造函數。 在父類沒有實現 Serializable 接口時,虛擬機是不會序列化父對象的,而一個 Java 對象的構造必須先有父對象,才有子對象,反序列化也不例外。所以反序列化時,為了構造父對象,只能調用父類的無參構造函數作為默認的父對象。因此當我們取 父對象的變量值時,它的值是調用父類無參構造函數后的值。如果你考慮到這種序列化的情況,在父類無參構造函數中對變量進行初始化,否則的話,父類變量值都 是默認聲明的值,如 int 型的默認是 0,string 型的默認是 null。

Transient 關鍵字的作用是控制變量的序列化,在變量聲明前加上該關鍵字,可以阻止該變量被序列化到文件中,在被反序列化后,transient 變量的值被設為初始值,如 int 型的是 0,對象型的是 null。

特性使用案例

我們熟悉使用 Transient 關鍵字可以使得字段不被序列化,那么還有別的方法嗎?根據父類對象序列化的規則,我們可以將不需要被序列化的字段抽取出來放到父類中,子類實現 Serializable 接口,父類不實現,根據父類序列化規則,父類的字段數據將不被序列化,形成類圖如圖 2 所示。

上圖中可以看出,attr1、attr2、attr3、attr5 都不會被序列化,放在父類中的好處在于當有另外一個 Child 類時,attr1、attr2、attr3 依然不會被序列化,不用重復抒寫 transient,代碼簡潔。

對敏感字段加密

情境:服務器端給客戶端發送序列化對象數據,對象中有一些數據是敏感的,比如密碼字符串等,希望對該密碼字段在序列化時,進行加密,而客戶端如果擁有解密的密鑰,只有在客戶端進行反序列化時,才可以對密碼進行讀取,這樣可以一定程度保證序列化對象的數據安全。

解決:在序列化過程中,虛擬機會試圖調用對象類里的 writeObject 和 readObject 方法,進行用戶自定義的序列化和反序列化,如果沒有這樣的方法,則默認調用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用戶自定義的 writeObject 和 readObject 方法可以允許用戶控制序列化的過程,比如可以在序列化的過程中動態改變序列化的數值。基于這個原理,可以在實際應用中得到使用,用于敏感字段的加密工作, 清單 3 展示了這個過程。

?

private static final long serialVersionUID = 1L;private String password = "pass";public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}private void writeObject(ObjectOutputStream out) {try {PutField putFields = out.putFields();System.out.println("原密碼:" + password);password = "encryption";//模擬加密putFields.put("password", password);System.out.println("加密后的密碼" + password);out.writeFields();} catch (IOException e) {e.printStackTrace();}}private void readObject(ObjectInputStream in) {try {GetField readFields = in.readFields();Object object = readFields.get("password", "");System.out.println("要解密的字符串:" + object.toString());password = "pass";//模擬解密,需要獲得本地的密鑰} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}public static void main(String[] args) {try {ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("result.obj"));out.writeObject(new Test());out.close();ObjectInputStream oin = new ObjectInputStream(new FileInputStream("result.obj"));Test t = (Test) oin.readObject();System.out.println("解密后的字符串:" + t.getPassword());oin.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}

在清單 3 的 writeObject 方法中,對密碼進行了加密,在 readObject 中則對 password 進行解密,只有擁有密鑰的客戶端,才可以正確的解析出密碼,確保了數據的安全。執行清單 3 后控制臺輸出如圖 3 所示。

特性使用案例

RMI 技術是完全基于 Java 序列化技術的,服務器端接口調用所需要的參數對象來至于客戶端,它們通過網絡相互傳輸。這就涉及 RMI 的安全傳輸的問題。一些敏感的字段,如用戶名密碼(用戶登錄時需要對密碼進行傳輸),我們希望對其進行加密,這時,就可以采用本節介紹的方法在客戶端對密 碼進行加密,服務器端進行解密,確保數據傳輸的安全性。

序列化存儲規則

情境:問題代碼如清單 3 所示。

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();//判斷兩個引用是否指向同一個對象System.out.println(t1 == t2);

清單 3 中對同一對象兩次寫入文件,打印出寫入一次對象后的存儲大小和寫入兩次后的存儲大小,然后從文件中反序列化出兩個對象,比較這兩個對象是否為同一對象。一 般的思維是,兩次寫入對象,文件大小會變為兩倍的大小,反序列化時,由于從文件讀取,生成了兩個對象,判斷相等時應該是輸入 false 才對,但是最后結果輸出如圖 4 所示。

我們看到,第二次寫入對象時文件只增加了 5 字節,并且兩個對象是相等的,這是為什么呢?

解答:Java 序列化機制為了節省磁盤空間,具有特定的存儲規則,當寫入文件的為同一對象時,并不會再將對象的內容進行存儲,而只是再次存儲一份引用,上面增加的 5 字節的存儲空間就是新增引用和一些控制信息的空間。反序列化時,恢復引用關系,使得清單 3 中的 t1 和 t2 指向唯一的對象,二者相等,輸出 true。該存儲規則極大的節省了存儲空間。

特性案例分析

查看清單 4 的代碼。

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 屬性值。案例代碼的目的原本是希望一次性傳輸對象修改前后的狀態。

結果兩個輸出的都是 1, 原因就是第一次寫入對象以后,第二次再試圖寫的時候,虛擬機根據引用關系知道已經有一個相同對象已經寫入文件,因此只保存第二次寫的引用,所以讀取時,都 是第一次保存的對象。讀者在使用一個文件多次 writeObject 需要特別注意這個問題。

?

轉載于:https://www.cnblogs.com/yiludugufei/p/4465274.html

總結

以上是生活随笔為你收集整理的java serializable深入了解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 91免费福利视频 | 伊人五月婷婷 | 日韩乱论 | 久久天天干 | 男人久久天堂 | 97超碰人人模人人人爽人人爱 | 视频一区二区国产 | 动漫av一区二区三区 | 日韩五十路 | 欧美插插视频 | 国产成人自拍视频在线观看 | 成人网在线看 | 51嘿嘿嘿国产精品伦理 | 激情五月婷婷色 | 国产精品无码一区二区三 | 久久99精品国产麻豆婷婷 | 中国大陆高清aⅴ毛片 | 免费观看黄色 | av毛片大全| 日本成人激情视频 | 午夜视频在线 | 亚洲国产视频一区二区三区 | 久久资源av | 中国三级黄色 | 久久亚洲综合国产精品99麻豆精品福利 | 色www亚洲国产张柏芝 | 蜜臀视频网站 | 狠狠干夜夜干 | 国产精品自拍片 | 高清视频在线免费观看 | 久久98 | 亚洲综合在线成人 | 亚洲无人区码一码二码三码 | 中文字幕在线视频观看 | 免费黄视频在线观看 | 日本少妇一区二区三区 | 永久av在线免费观看 | 人操人人 | 99久久99久久精品国产片果冰 | 黑人糟蹋人妻hd中文字幕 | 99在线小视频 | 果冻传媒18禁免费视频 | 蜜色av | 日韩一区二区三区免费视频 | 中文字幕久久综合 | 灌满闺乖女h高h调教尿h | 人妻aⅴ无码一区二区三区 阿v免费视频 | 国产精品视频一区在线观看 | 国产一级片在线 | 四虎影视免费永久观看在线 | 日日拍夜夜拍 | 99热这里只有精品2 91免费版黄 | 激情小说图片视频 | 人人草网 | 奇米一区| 亚洲毛片久久 | 午夜亚洲AV永久无码精品蜜芽 | 国产一级在线视频 | 久久深夜视频 | 亚洲妇女av | 青青草手机在线视频 | 扒开jk护士狂揉免费 | 越南av| 国产精品国产一区二区三区四区 | a天堂在线观看视频 | 国精产品一区一区三区mba下载 | 狠狠干狠狠操视频 | 日韩精品一区二区在线 | 国产亚洲精品成人无码精品网站 | 亚洲视频中文字幕在线观看 | 欧美成人高清 | 国产第九页 | 女人的av | 超碰人人在线观看 | 色爱av| 美女被出白浆 | 99在线观看视频 | 波多野结衣一区二区三区在线 | 国产精久久一区二区三区 | 久久在线中文字幕 | www.白虎 | 精品成人一区二区三区久久精品 | 国产精品久久久久久久久久久久午夜片 | 天堂网在线观看视频 | 国产人妻人伦精品1国产盗摄 | 日本亚洲黄色 | 看黄色一级视频 | 亚洲色图日韩 | 精品国产综合区久久久久久 | 午夜视频福利在线 | 99热这里只有精品在线 | 国产1区 | 女女高潮h冰块play失禁百合 | 少妇综合| 日本一区三区 | 中文字幕mv | 国内精品久久久久久久 | 亚洲一区二区三区91 | 日韩成人一级 |