序列化和反序列化作為Java里一個(gè)較為基礎(chǔ)的知識點(diǎn),大家心里也有那么幾句要說的,但我相信很多小伙伴掌握的也就是那么幾句而已,如果再深究問一下Java如何實(shí)現(xiàn)序列化和反序列化的,就可能不知所措了!遙記當(dāng)年也被問了這一個(gè)問題,自信滿滿的說了一大堆,什么是序列化、什么是反序列化、什么場景的時(shí)候才會(huì)用到等,然后面試官說:那你能說一下序列化和反序列化底層是如何實(shí)現(xiàn)的嗎?一臉懵逼,然后回家等通知!結(jié)果自然是涼了~
創(chuàng)新互聯(lián)專注于企業(yè)成都全網(wǎng)營銷推廣、網(wǎng)站重做改版、安源網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5網(wǎng)站設(shè)計(jì)、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為安源等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
1、什么是序列化和反序列化
(1)Java序列化是指把Java對象轉(zhuǎn)換為字節(jié)序列的過程,而Java反序列化是指把字節(jié)序列恢復(fù)為Java對象的過程;
(2)序列化:對象序列化的最主要的用處就是在傳遞和保存對象的時(shí)候,保證對象的完整性和可傳遞性。序列化是把對象轉(zhuǎn)換成有序字節(jié)流,以便在網(wǎng)絡(luò)上傳輸或者保存在本地文件中。序列化后的字節(jié)流保存了Java對象的狀態(tài)以及相關(guān)的描述信息。序列化機(jī)制的核心作用就是對象狀態(tài)的保存與重建。
(3)反序列化:客戶端從文件中或網(wǎng)絡(luò)上獲得序列化后的對象字節(jié)流后,根據(jù)字節(jié)流中所保存的對象狀態(tài)及描述信息,通過反序列化重建對象。
(4)本質(zhì)上講,序列化就是把實(shí)體對象狀態(tài)按照一定的格式寫入到有序字節(jié)流,反序列化就是從有序字節(jié)流重建對象,恢復(fù)對象狀態(tài)。
2、為什么需要序列化與反序列化
我們知道,當(dāng)兩個(gè)進(jìn)程進(jìn)行遠(yuǎn)程通信時(shí),可以相互發(fā)送各種類型的數(shù)據(jù),包括文本、圖片、音頻、視頻等, 而這些數(shù)據(jù)都會(huì)以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳送。
那么當(dāng)兩個(gè)Java進(jìn)程進(jìn)行通信時(shí),能否實(shí)現(xiàn)進(jìn)程間的對象傳送呢?答案是可以的!如何做到呢?這就需要Java序列化與反序列化了!
換句話說,一方面,發(fā)送方需要把這個(gè)Java對象轉(zhuǎn)換為字節(jié)序列,然后在網(wǎng)絡(luò)上傳送;另一方面,接收方需要從字節(jié)序列中恢復(fù)出Java對象。
當(dāng)我們明晰了為什么需要Java序列化和反序列化后,我們很自然地會(huì)想Java序列化的好處。其好處一是實(shí)現(xiàn)了數(shù)據(jù)的持久化,通過序列化可以把數(shù)據(jù)永久地保存到硬盤上(通常存放在文件里),二是,利用序列化實(shí)現(xiàn)遠(yuǎn)程通信,即在網(wǎng)絡(luò)上傳送對象的字節(jié)序列。
總的來說可以歸結(jié)為以下幾點(diǎn):
(1)永久性保存對象,保存對象的字節(jié)序列到本地文件或者數(shù)據(jù)庫中;
(2)通過序列化以字節(jié)流的形式使對象在網(wǎng)絡(luò)中進(jìn)行傳遞和接收;
(3)通過序列化在進(jìn)程間傳遞對象;
3、序列化算法一般會(huì)按步驟做如下事情:
(1)將對象實(shí)例相關(guān)的類元數(shù)據(jù)輸出。
(2)遞歸地輸出類的超類描述直到不再有超類。
(3)類元數(shù)據(jù)完了以后,開始從最頂層的超類開始輸出對象實(shí)例的實(shí)際數(shù)據(jù)值。
(4)從上至下遞歸輸出實(shí)例的數(shù)據(jù)
1、JDK類庫中序列化和反序列化API
(1)java.io.ObjectOutputStream:表示對象輸出流;
它的writeObject(Object obj)方法可以對參數(shù)指定的obj對象進(jìn)行序列化,把得到的字節(jié)序列寫到一個(gè)目標(biāo)輸出流中;
(2)java.io.ObjectInputStream:表示對象輸入流;
它的readObject()方法源輸入流中讀取字節(jié)序列,再把它們反序列化成為一個(gè)對象,并將其返回;
2、實(shí)現(xiàn)序列化的要求
只有實(shí)現(xiàn)了Serializable或Externalizable接口的類的對象才能被序列化,否則拋出異常!
3、實(shí)現(xiàn)Java對象序列化與反序列化的方法
假定一個(gè)User類,它的對象需要序列化,可以有如下三種方法:
(1)若User類僅僅實(shí)現(xiàn)了Serializable接口,則可以按照以下方式進(jìn)行序列化和反序列化
ObjectOutputStream采用默認(rèn)的序列化方式,對User對象的非transient的實(shí)例變量進(jìn)行序列化。
ObjcetInputStream采用默認(rèn)的反序列化方式,對對User對象的非transient的實(shí)例變量進(jìn)行反序列化。
(2)若User類僅僅實(shí)現(xiàn)了Serializable接口,并且還定義了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),則采用以下方式進(jìn)行序列化與反序列化。
ObjectOutputStream調(diào)用User對象的writeObject(ObjectOutputStream out)的方法進(jìn)行序列化。
ObjectInputStream會(huì)調(diào)用User對象的readObject(ObjectInputStream in)的方法進(jìn)行反序列化。
(3)若User類實(shí)現(xiàn)了Externalnalizable接口,且User類必須實(shí)現(xiàn)readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,則按照以下方式進(jìn)行序列化與反序列化。
ObjectOutputStream調(diào)用User對象的writeExternal(ObjectOutput out))的方法進(jìn)行序列化。
ObjectInputStream會(huì)調(diào)用User對象的readExternal(ObjectInput in)的方法進(jìn)行反序列化。
4、JDK類庫中序列化的步驟
步驟一:創(chuàng)建一個(gè)對象輸出流,它可以包裝一個(gè)其它類型的目標(biāo)輸出流,如文件輸出流:
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\object.out"));
步驟二:通過對象輸出流的writeObject()方法寫對象:
oos.writeObject(new User("xuliugen", "123456", "male"));
5、JDK類庫中反序列化的步驟
步驟一:創(chuàng)建一個(gè)對象輸入流,它可以包裝一個(gè)其它類型輸入流,如文件輸入流:
ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));
步驟二:通過對象輸出流的readObject()方法讀取對象:
User user = (User) ois.readObject();
說明:為了正確讀取數(shù)據(jù),完成反序列化,必須保證向?qū)ο筝敵隽鲗憣ο蟮捻樞蚺c從對象輸入流中讀對象的順序一致。
6、序列化和反序列化的示例
為了更好地理解Java序列化與反序列化,舉一個(gè)簡單的示例如下:
public class SerialDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化
FileOutputStream fos = new FileOutputStream("object.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
User user1 = new User("xuliugen", "123456", "male");
oos.writeObject(user1);
oos.flush();
oos.close();
//反序列化
FileInputStream fis = new FileInputStream("object.out");
ObjectInputStream ois = new ObjectInputStream(fis);
User user2 = (User) ois.readObject();
System.out.println(user2.getUserName()+ " " +
user2.getPassword() + " " + user2.getSex());
//反序列化的輸出結(jié)果為:xuliugen 123456 male
}
}
public class User implements Serializable {
private String userName;
private String password;
private String sex;
//全參構(gòu)造方法、get和set方法省略
}
object.out文件如下(使用UltraEdit打開):
注:上圖中0000000h-000000c0h表示行號;0-f表示列;行后面的文字表示對這行16進(jìn)制的解釋;對上述字節(jié)碼所表述的內(nèi)容感興趣的可以對照相關(guān)的資料,查閱一下每一個(gè)字符代表的含義,這里不在探討!
類似于我們Java代碼編譯之后的.class文件,每一個(gè)字符都代表一定的含義。序列化和反序列化的過程就是生成和解析上述字符的過程!
序列化圖示:
反序列化圖示:
1、序列化時(shí),只對對象的狀態(tài)進(jìn)行保存,而不管對象的方法;
2、當(dāng)一個(gè)父類實(shí)現(xiàn)序列化,子類自動(dòng)實(shí)現(xiàn)序列化,不需要顯式實(shí)現(xiàn)Serializable接口;
3、當(dāng)一個(gè)對象的實(shí)例變量引用其他對象,序列化該對象時(shí)也把引用對象進(jìn)行序列化;
4、并非所有的對象都可以序列化,至于為什么不可以,有很多原因了,比如:
安全方面的原因,比如一個(gè)對象擁有private,public等field,對于一個(gè)要傳輸?shù)膶ο螅热鐚懙轿募?,或者進(jìn)行RMI傳輸?shù)鹊龋谛蛄谢M(jìn)行傳輸?shù)倪^程中,這個(gè)對象的private等域是不受保護(hù)的;
5、聲明為static和transient類型的成員數(shù)據(jù)不能被序列化。因?yàn)閟tatic代表類的狀態(tài),transient代表對象的臨時(shí)數(shù)據(jù)。
6、序列化運(yùn)行時(shí)使用一個(gè)稱為 serialVersionUID 的版本號與每個(gè)可序列化類相關(guān)聯(lián),該序列號在反序列化過程中用于驗(yàn)證序列化對象的發(fā)送者和接收者是否為該對象加載了與序列化兼容的類。為它賦予明確的值。顯式地定義serialVersionUID有兩種用途:
在某些場合,希望類的不同版本對序列化兼容,因此需要確保類的不同版本具有相同的serialVersionUID;
7、Java有很多基礎(chǔ)類已經(jīng)實(shí)現(xiàn)了serializable接口,比如String,Vector等。但是也有一些沒有實(shí)現(xiàn)serializable接口的;
8、如果一個(gè)對象的成員變量是一個(gè)對象,那么這個(gè)對象的數(shù)據(jù)成員也會(huì)被保存!這是能用序列化解決深拷貝的重要原因;
看到這里,可能已經(jīng)讓我們很滿足了,畢竟已經(jīng)知道了我們平時(shí)使用的序列化和反序列化是如何進(jìn)行操作的,Java給我們提供了哪些接口可供使用,也比我們最初知道的簡單的什么是序列化、反序列化以及作用多了很多!后續(xù)內(nèi)容我們也會(huì)不斷再討論和更新!
本文標(biāo)題:序列化和反序列化的底層實(shí)現(xiàn)原理是什么?
網(wǎng)頁鏈接:http://jinyejixie.com/article26/gpsgcg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、微信小程序、網(wǎng)站改版、云服務(wù)器、品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站收錄
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)