Java基礎系列8:Java的序列化與反序列化(修)

一 簡介

對象序列化就是把一個對象變成二進制的數據流的一種方法,通過對象序列化可以方便地實現對象的傳輸和存儲。

把對象轉換為字節序列的過程稱為對象的序列化

把字節序列恢復為對象的過程稱為對象的反序列化

對象的序列化主要有兩種用途:
1) 把對象的字節序列永久地保存到硬盤上,通常存放在一個文件中;
2) 在網絡上傳送對象的字節序列。

對象序列化包括如下步驟:
1) 創建一個對象輸出流,它可以包裝一個其他類型的目標輸出流,如文件輸出流;
2) 通過對象輸出流的writeObject()方法寫對象。

對象反序列化包括如下步驟:
1) 創建一個對象輸入流,它可以包裝一個其他類型的源輸入流,如文件輸入流;
2) 通過對象輸入流的readObject()方法讀取對象。

在很多應用中,需要對某些對象進行序列化,讓它們離開內存空間,入住物理硬盤,以便長期保存。比如最常見的是Web服務器中的Session對象,當有 10萬用戶并發訪問,就有可能出現10萬個Session對象,內存可能吃不消,于是Web容器就會把一些seesion先序列化到硬盤中,等要用了,再把保存在硬盤中的對象還原到內存中。

當兩個進程在進行遠程通信時,彼此可以發送各種類型的數據。無論是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方需要把這個Java對象轉換為字節序列,才能在網絡上傳送;接收方則需要把字節序列再恢復為Java對象。


二 Java中的序列化API

如果一個類的對象想被序列化,那么該對象所在的類必須實現java.io.Serializable接口,此接口的定義如下:

public interface Serializable{}

可以發現此接口并沒有定義任何的方法,只是一個標識接口,表示一個類可以被序列化,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package?cn.zifangsky.serializable;
import?java.io.Serializable;
public?class?Person?implements?Serializable?{
????private?static?final?long?serialVersionUID?=?2651243789670519969L;
????private?String?name;
????private?int?age;
????public?Person(String?name,?int?age)?{
????????this.name?=?name;
????????this.age?=?age;
????}
????public?String?toString()?{
????????return?"Person?[name="?+?name?+?",?age="?+?age?+?"]";
????}
}

就像上面這個Person類一樣,實現了序列化接口表明此類的對象可以經過二進制的數據流進行傳輸了。但是如果想要完成對象的輸入和輸出,還需要借助對象輸出流(ObjectOutputStream)和對象輸入流(ObjectInputStream)

java.io.ObjectOutputStream代表對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把得到的字節序列寫到一個目標輸出流中;java.io.ObjectInputStream代表對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化為一個對象,并將其返回

只有實現了Serializable或Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自 Serializable接口,實現Externalizable接口的類完全由自身來控制序列化的行為,而僅實現Serializable接口的類可以 采用默認的序列化方式 。


三 使用Serializable接口實現的實例

首先定義了一個實現了Serializable接口WebSite的實體類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package?cn.zifangsky.serializable;
import?java.io.Serializable;
public?class?WebSite?implements?Serializable?{
????private?static?final?long?serialVersionUID?=?1835573222135484360L;
????private?String?siteName;
????private?String?siteUrl;
????private?String?webMaster;
????public?WebSite()?{
????}
????public?WebSite(String?siteName,?String?siteUrl,?String?webMaster)?{
????????this.siteName?=?siteName;
????????this.siteUrl?=?siteUrl;
????????this.webMaster?=?webMaster;
????}
????public?String?getSiteName()?{
????????return?siteName;
????}
????public?void?setSiteName(String?siteName)?{
????????this.siteName?=?siteName;
????}
????public?String?getSiteUrl()?{
????????return?siteUrl;
????}
????public?void?setSiteUrl(String?siteUrl)?{
????????this.siteUrl?=?siteUrl;
????}
????public?String?getWebMaster()?{
????????return?webMaster;
????}
????public?void?setWebMaster(String?webMaster)?{
????????this.webMaster?=?webMaster;
????}
????public?String?toString()?{
????????return?"WebSite?[siteName="?+?siteName?+?",?siteUrl="?+?siteUrl?+?",?webMaster="?+?webMaster?+?"]";
????}
}

然后進行序列化和反序列化測試:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package?cn.zifangsky.serializable;
import?java.io.File;
import?java.io.FileInputStream;
import?java.io.FileNotFoundException;
import?java.io.FileOutputStream;
import?java.io.IOException;
import?java.io.ObjectInputStream;
import?java.io.ObjectOutputStream;
public?class?TestSerialize?{
????public?static?void?main(String[]?args)?throws?FileNotFoundException,?IOException,?ClassNotFoundException?{
????????TestSerialize.serializeWebSite();
????????TestSerialize.deserializeWebSite();
????}
?????
????/**
?????*?使用ObjectOutputStream?序列化WebSite
?????*?@throws?IOException?
?????*?@throws?FileNotFoundException?
?????*?
?????*?*/
????public?static?void?serializeWebSite()?throws?FileNotFoundException,?IOException{
????????WebSite?webSite?=?new?WebSite();
????????webSite.setSiteName("zifangsky的個人博客");
????????webSite.setSiteUrl("http://www.zifangsky.cn");
????????webSite.setWebMaster("zifangsky");
?????????
????????//序列化
????????ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(new?FileOutputStream(new?File("C:/Users/Administrator/Desktop/test.txt")));
????????objectOutputStream.writeObject(webSite);
????????objectOutputStream.flush();
????????objectOutputStream.close();
????}
?????
????/**
?????*?使用ObjectInputStream?反序列化WebSite
?????*?@throws?IOException?
?????*?@throws?FileNotFoundException?
?????*?@throws?ClassNotFoundException?
?????*?
?????*?*/
????public?static?void?deserializeWebSite()?throws?FileNotFoundException,?IOException,?ClassNotFoundException{
????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(new?FileInputStream(new?File("C:/Users/Administrator/Desktop/test.txt")));
????????//反序列化
????????WebSite?webSite?=?(WebSite)?objectInputStream.readObject();
????????objectInputStream.close();
????????System.out.println(webSite);
????}
?????
}

輸出:

1
WebSite?[siteName=zifangsky的個人博客,?siteUrl=http://www.zifangsky.cn,?webMaster=zifangsky]

四?使用Externalizable接口實現的實例

被Serializable接口聲明的類的對象的內容都將被序列化,如果現在用戶希望自己制定序列化的內容,則可以讓一個類實現Externalizable接口,此接口的定義如下:

public interface Externalizable extends java.io.Serializable {
?
? ? void writeExternal(ObjectOutput out) throws IOException;

? ? void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

其中,這兩個方法的作用是:

i)writeExternal(ObjectOutput out)?:在此方法中制定要保存的屬性信息,對象序列化時調用

ii)readExternal(ObjectInput in)?: 在此方法中讀取被保存的信息,對象反序列化時調用


下面將以一個具體的實例來簡單說明序列化和反序列化過程:

(1)實現了Externalizable接口的實體類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package?cn.zifangsky.serializable;
import?java.io.Externalizable;
import?java.io.IOException;
import?java.io.ObjectInput;
import?java.io.ObjectOutput;
public?class?ExternalizableDemo?implements?Externalizable{
????private?String?name;
????static?{
????????System.out.println("調用靜態代碼塊");
????}
????public?ExternalizableDemo()?{
????????System.out.println("調用無參構造方法");
????}
????public?ExternalizableDemo(String?name)?{
????????this.name?=?name;
????????System.out.println("調用有參構造方法");
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?String?toString()?{
????????return?"ExternalizableDemo?[name="?+?name?+?"]";
????}
?????
????/**
?????*?ObjectOutputStream會調用writeExternal(ObjectOutput?out))這個方法進行序列化
?????*?*/
????public?void?writeExternal(ObjectOutput?out)?throws?IOException?{
????????out.writeObject(name);
????}
????/**
?????*?ObjectInputStream會調用readExternal(ObjectInput?in)這個方法進行反序列化
?????*?*/
????public?void?readExternal(ObjectInput?in)?throws?IOException,?ClassNotFoundException?{
????????name?=?(String)?in.readObject();
????}
}

(2)然后進行序列化和反序列化測試:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package?cn.zifangsky.serializable;
import?java.io.File;
import?java.io.FileInputStream;
import?java.io.FileNotFoundException;
import?java.io.FileOutputStream;
import?java.io.IOException;
import?java.io.ObjectInputStream;
import?java.io.ObjectOutputStream;
public?class?TestExternalizable?{
????public?static?void?main(String[]?args)?throws?FileNotFoundException,?IOException,?ClassNotFoundException?{
????????ExternalizableDemo?demo?=?new?ExternalizableDemo("hello");
????????//?序列化
????????ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(
????????????????new?FileOutputStream(new?File("C:/Users/Administrator/Desktop/test2.txt")));
????????objectOutputStream.writeObject(demo);
????????objectOutputStream.flush();
????????objectOutputStream.close();
?????????
????????//反序列化
????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(new?FileInputStream(new?File("C:/Users/Administrator/Desktop/test2.txt")));
????????ExternalizableDemo?demo2?=?(ExternalizableDemo)?objectInputStream.readObject();
????????objectInputStream.close();
????????System.out.println(demo2);?????
????}
}

輸出:

1
2
3
4
調用靜態代碼塊
調用有參構造方法
調用無參構造方法
ExternalizableDemo?[name=hello]

注:

(1)使用Externalizable進行序列化時,當讀取對象時,會調用被序列化類的無參構造器去創建一個新的對象,然后再將被保存對象的字段的值分別填充到新對象中

(2)Externalizable接口與Serializable接口實現序列化的區別:

區別SerializableExternalizable
實現負責度實現簡單,Java對其有內建支持實現負責,由開發人員自己完成
執行效率所有對象由Java統一保存,性能較低開發人員自己決定保存那些對象,可能造成速度提升
保存信息保存時占用空間大部分存儲,可能造成空間減小

(3)一個對象被序列化后,到底哪些內容被保存了下來,是屬性還是方法?

答:只有屬性被序列化。因為每個對象都有相同的方法,但是每個對象的屬性卻不一定相同,因此對象保存的只有屬性信息,那么同樣道理在進行序列化操作時也只有屬性被序列化


五 transient關鍵字

當使用Serializable接口實現序列化操作時,如果一個對象中的某個屬性不希望被序列化,那么就可以使用transient關鍵字進行聲明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package?cn.zifangsky.serializable;
import?java.io.Serializable;
public?class?WebSite?implements?Serializable?{
????private?static?final?long?serialVersionUID?=?1835573222135484360L;
????private?String?siteName;
????private?String?siteUrl;
????private?transient?String?webMaster;
????public?WebSite(String?siteName,?String?siteUrl,?String?webMaster)?{
????????this.siteName?=?siteName;
????????this.siteUrl?=?siteUrl;
????????this.webMaster?=?webMaster;
????}
????public?String?toString()?{
????????return?"WebSite?[siteName="?+?siteName?+?",?siteUrl="?+?siteUrl?+?",?webMaster="?+?webMaster?+?"]";
????}
}

在上面這個類中,不希望webMaster這個屬性被序列化,因此把它用transient關鍵字進行修飾,接下來就是序列化與反序列化測試:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package?cn.zifangsky.serializable;
import?java.io.File;
import?java.io.FileInputStream;
import?java.io.FileNotFoundException;
import?java.io.FileOutputStream;
import?java.io.IOException;
import?java.io.ObjectInputStream;
import?java.io.ObjectOutputStream;
public?class?TestSerialize?{
????public?static?void?main(String[]?args)?throws?FileNotFoundException,
????????????IOException,?ClassNotFoundException?{
????????TestSerialize.serializeWebSite();
????????TestSerialize.deserializeWebSite();
????}
????/**
?????*?使用ObjectOutputStream?序列化WebSite
?????*?
?????*?@throws?IOException
?????*?@throws?FileNotFoundException
?????*?
?????*?*/
????public?static?void?serializeWebSite()?throws?FileNotFoundException,
????????????IOException?{
????????WebSite?webSite?=?new?WebSite("zifangsky的個人博客","http://www.zifangsky.cn","zifangsky");
????????//?序列化
????????ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(
????????????????new?FileOutputStream(new?File(
????????????????????????"C:/Users/Administrator/Desktop/test.txt")));
????????objectOutputStream.writeObject(webSite);
????????objectOutputStream.flush();
????????objectOutputStream.close();
????}
????/**
?????*?使用ObjectInputStream?反序列化WebSite
?????*?
?????*?@throws?IOException
?????*?@throws?FileNotFoundException
?????*?@throws?ClassNotFoundException
?????*?
?????*?*/
????public?static?void?deserializeWebSite()?throws?FileNotFoundException,
????????????IOException,?ClassNotFoundException?{
????????ObjectInputStream?objectInputStream?=?new?ObjectInputStream(
????????????????new?FileInputStream(new?File(
????????????????????????"C:/Users/Administrator/Desktop/test.txt")));
????????//?反序列化
????????WebSite?webSite?=?(WebSite)?objectInputStream.readObject();
????????objectInputStream.close();
????????System.out.println(webSite);
????}
}

輸出:

1
WebSite?[siteName=zifangsky的個人博客,?siteUrl=http://www.zifangsky.cn,?webMaster=null]

從上面的輸出可以看出,webMaster這個屬性并沒有被序列化




本文轉自 pangfc 51CTO博客,原文鏈接:http://blog.51cto.com/983836259/1758247,如需轉載請自行聯系原作者

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285247.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285247.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285247.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉]nginx學習,看這一篇就夠了:下載、安裝。使用:正向代理、反向代理、負載均衡。常用命令和配置文件

文章目錄 前言一、nginx簡介 1. 什么是 nginx 和可以做什么事情2.Nginx 作為 web 服務器3. 正向代理4. 反向代理5. 負載均衡6.動靜分離二、Nginx 的安裝(Linux:centos為例) 1. 準備工作2. 開始安裝3. 運行nginx4. 防火墻問題三、 Nginx 的常用命令和配置文件 1. Nginx常用命令 …

在 .NET 6 中使用 Startup.cs 更簡潔的方法

如果您在關注 .NET 6,那么您應該知道,在 .NET 6 項目中,沒有 Startup.cs 文件,現在使用了 Program.cs 文件來完成統一的配置。我之前發了一篇使用在 .NET 6 項目中使用 Startup.cs 的文章。在 .NET 6 項目中使用 Startup.cs能否能…

【ArcGIS Pro微課1000例】0005:ArcGIS Pro 2.5基于矢量數據制作拉伸三維地圖案例

ArcGIS Pro 2.5中,可以基于某個字段,對矢量數據進行拉伸,制作精美的三維地圖。本文以中國省級行政區劃數據為例,基于面積字段制作3d地圖。 文章目錄 1. 新建局部場景2. 地圖符號化3. 三維矢量地圖制作1. 新建局部場景 打開ArcGIS Pro 2.5,新建局部場景項目,并保存。 2. …

C語言試題144之編寫函數輸入,輸出 5 個學生的數據記錄。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:編寫 input()和 output()函數…

第十一次實驗總結

知識點總結: 指針、數組和地址間的關系 數組的基地址是在內存中存儲數組的起始位置,它是數組中第一個元素(下標為0)的地址,因此數組名本身是一個地址即指針值。 指針是以地址作為值的變量,而數組名的值是一…

Python統計列表中的重復項出現的次數的方法

本文實例展示了Python統計列表中的重復項出現的次數的方法,是一個很實用的功能,適合Python初學者學習借鑒。具體方法如下: 對一個列表,比如[1,2,2,2,2,3,3,3,4,4,4,4],現在我們需要統計這個列表里的重復項,…

分布式(一致性協議)之領導人選舉( DotNext.Net.Cluster 實現Raft 選舉 )

分布式(一致性協議)之領導人選舉( DotNext.Net.Cluster 實現Raft 選舉 )繼分布式鎖之后的又一高可用技術爽文之分布式領導選舉 或者說 分布式一致性協議的實現分布式選舉是實現高可用的必備技術,想實現主從,就必須得有選舉的策略,有主從才會有…

投巧解決JavaScript split方法出現空字符的問題

直接使用split,前后各有一個“”值。 >> var str,a,b,c,d,e,f,; >> str.split(,);//(8) ["", "a", "b", "c", "d", "e", "f", ""]臨時方法:split后&…

C語言試題146之反向輸出一個鏈表

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:反向輸出一個鏈表 2 、溫馨提…

【ArcGIS Pro微課1000例】0006:ArcGIS Pro 2.5三維顯示DEM數字高程模型

通過ArcGIS的學習,我們知道,ArcScene可以實現二維數據的三維顯示,是將二維數據(例如DEM)進行自定義表面浮動拉伸。那么ArcGIS Pro中能不能實現DEM的三維顯示呢? ArcScene三維顯示結果: 目前所采用的ArcGIS Pro 2.5版本還不能直接將DEM進行三維顯示,我們的做法是參照Ar…

中國古代歷朝首都一覽

【五帝時期】(約公元前26世紀初—公元前2070年) 『黃帝』有熊(今河南鄭州新鄭) 『顓頊』帝丘(今河南濮陽) 『帝嚳』帝丘(今河南濮陽)、西亳(今河南洛陽偃師西&#xff09…

程序員的自我修養:有助于提高溝通能力的7本書

直接影響工作效率的四種能力:溝通能力、自學能力、自我管理能力、問題解決能力。提高溝通能力,是程序員提高自我修養的必要條件。相信很多人跟我一樣,性格內向,信仰技術,很少有跟人說話的愿望,只是想看代碼…

玩轉 Linux 之:磁盤分區、掛載知多少?

轉載于:http://my.oschina.net/leejun2005/blog/290073 在做日志機擴容的時候,發現運維同學將一塊硬盤的掛載點沒有同以前的日志機保持一致,考慮到這會給日后的維護帶來麻煩,于是嘗試著手修改,在修改的同時&#xff0c…

C# NanoFramework 點燈和按鍵 之 ESP32

本來周末是要搞個大的,WIFI 和 Web網頁之類的,奈何搞了兩天,并與外國友人聊過后,才發現是固件有問題,晚上與大佬進行交流后才發現,原來ESP32S的官方固件有問題,搞不了。所以,建議買的…

【ArcGIS Pro微課1000例】0002:ArcGIS Pro 2.5二三維聯動顯示

ArcGIS Pro是一款全新的桌面應用程序,它改變了桌面GIS的工作方式,以滿足新一代WebGIS應用模式。ArcGIS Pro采用Ribbon界面風格,給人全新的用戶體驗。它作為一個高級的應用程序,可以對來自本地、ArcGIS Online、或者Portal for ArcGIS的數據進行可視化、編輯、分析。同時,實…

Spring Boot 解決跨域Cors問題

后端主要代碼: (http://localhost:8080/ ) /*WebCorsConfig.java*/ package com.example.demo.Controller;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsR…

C語言試題147之創建一個鏈表并且排序輸出這個鏈表

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:創建一個鏈表并且排序輸出這…

DOM節點創建(jQuery)

1DOM創建節點及節點屬性 通過JavaScript可以很方便的獲取DOM節點,從而進行一系列的DOM操作。但實際上一般開發者都習慣性的先定義好HTML結構,但這樣就非常不靈活了。 試想下這樣的情況:如果我們通過AJAX獲取到數據之后然后才能確定結構的話&a…

PHP中刷新輸出緩沖

2019獨角獸企業重金招聘Python工程師標準>>> http://www.cnblogs.com/mutuan/archive/2012/03/18/2404957.html 轉載于:https://my.oschina.net/wuzhencan/blog/652259

2021最新計算機二級C語言試題

一、選擇題 (1) 下面敘述正確的是( C ) A. 算法的執行效率與數據的存儲結構無關 B. 算法的空間復雜度是指算法程序中指令(或語句)的條數 C. 算法的有窮性是指算法必須能在執行有限個步驟之后終止 D. 以上三種描述都不對 (2) 以下數據結構中不屬于線性數據結構的是( C ) A…