最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA序列化和反序列化的底層實(shí)現(xiàn)原理解析

 更新時(shí)間:2019年11月27日 14:38:39   作者:myseries  
這篇文章主要介紹了JAVA序列化和反序列化的底層實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

一、基本概念

1、什么是序列化和反序列化

?。?)Java序列化是指把Java對(duì)象轉(zhuǎn)換為字節(jié)序列的過(guò)程,而Java反序列化是指把字節(jié)序列恢復(fù)為Java對(duì)象的過(guò)程;

 (2)**序列化:**對(duì)象序列化的最主要的用處就是在傳遞和保存對(duì)象的時(shí)候,保證對(duì)象的完整性和可傳遞性。序列化是把對(duì)象轉(zhuǎn)換成有序字節(jié)流,以便在網(wǎng)絡(luò)上傳輸或者保存在本地文件中。序列化后的字節(jié)流保存了Java對(duì)象的狀態(tài)以及相關(guān)的描述信息。序列化機(jī)制的核心作用就是對(duì)象狀態(tài)的保存與重建。

 (3)**反序列化:**客戶端從文件中或網(wǎng)絡(luò)上獲得序列化后的對(duì)象字節(jié)流后,根據(jù)字節(jié)流中所保存的對(duì)象狀態(tài)及描述信息,通過(guò)反序列化重建對(duì)象。

 (4)本質(zhì)上講,序列化就是把實(shí)體對(duì)象狀態(tài)按照一定的格式寫(xiě)入到有序字節(jié)流,反序列化就是從有序字節(jié)流重建對(duì)象,恢復(fù)對(duì)象狀態(tài)。

2、為什么需要序列化與反序列化

  我們知道,當(dāng)兩個(gè)進(jìn)程進(jìn)行遠(yuǎn)程通信時(shí),可以相互發(fā)送各種類(lèi)型的數(shù)據(jù),包括文本、圖片、音頻、視頻等, 而這些數(shù)據(jù)都會(huì)以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳送。

  那么當(dāng)兩個(gè)Java進(jìn)程進(jìn)行通信時(shí),能否實(shí)現(xiàn)進(jìn)程間的對(duì)象傳送呢?答案是可以的!如何做到呢?這就需要Java序列化與反序列化了!

  換句話說(shuō),一方面,發(fā)送方需要把這個(gè)Java對(duì)象轉(zhuǎn)換為字節(jié)序列,然后在網(wǎng)絡(luò)上傳送;另一方面,接收方需要從字節(jié)序列中恢復(fù)出Java對(duì)象。

  當(dāng)我們明晰了為什么需要Java序列化和反序列化后,我們很自然地會(huì)想Java序列化的好處。其好處一是實(shí)現(xiàn)了數(shù)據(jù)的持久化,通過(guò)序列化可以把數(shù)據(jù)永久地保存到硬盤(pán)上(通常存放在文件里),二是,利用序列化實(shí)現(xiàn)遠(yuǎn)程通信,即在網(wǎng)絡(luò)上傳送對(duì)象的字節(jié)序列。

總的來(lái)說(shuō)可以歸結(jié)為以下幾點(diǎn):

(1)永久性保存對(duì)象,保存對(duì)象的字節(jié)序列到本地文件或者數(shù)據(jù)庫(kù)中;

(2)通過(guò)序列化以字節(jié)流的形式使對(duì)象在網(wǎng)絡(luò)中進(jìn)行傳遞和接收;

(3)通過(guò)序列化在進(jìn)程間傳遞對(duì)象;

3、序列化算法一般會(huì)按步驟做如下事情:

(1)將對(duì)象實(shí)例相關(guān)的類(lèi)元數(shù)據(jù)輸出。

(2)遞歸地輸出類(lèi)的超類(lèi)描述直到不再有超類(lèi)。

(3)類(lèi)元數(shù)據(jù)完了以后,開(kāi)始從最頂層的超類(lèi)開(kāi)始輸出對(duì)象實(shí)例的實(shí)際數(shù)據(jù)值。

(4)從上至下遞歸輸出實(shí)例的數(shù)據(jù)

二、Java如何實(shí)現(xiàn)序列化和反序列化

1、JDK類(lèi)庫(kù)中序列化和反序列化API

(1)java.io.ObjectOutputStream:表示對(duì)象輸出流;

  它的writeObject(Object obj)方法可以對(duì)參數(shù)指定的obj對(duì)象進(jìn)行序列化,把得到的字節(jié)序列寫(xiě)到一個(gè)目標(biāo)輸出流中;

(2)java.io.ObjectInputStream:表示對(duì)象輸入流;

  它的readObject()方法源輸入流中讀取字節(jié)序列,再把它們反序列化成為一個(gè)對(duì)象,并將其返回;

2、實(shí)現(xiàn)序列化的要求

  只有實(shí)現(xiàn)了Serializable或Externalizable接口的類(lèi)的對(duì)象才能被序列化,否則拋出異常!

3、實(shí)現(xiàn)Java對(duì)象序列化與反序列化的方法

假定一個(gè)User類(lèi),它的對(duì)象需要序列化,可以有如下三種方法:

(1)若User類(lèi)僅僅實(shí)現(xiàn)了Serializable接口,則可以按照以下方式進(jìn)行序列化和反序列化

  •   ObjectOutputStream采用默認(rèn)的序列化方式,對(duì)User對(duì)象的非transient的實(shí)例變量進(jìn)行序列化。
  •   ObjcetInputStream采用默認(rèn)的反序列化方式,對(duì)對(duì)User對(duì)象的非transient的實(shí)例變量進(jìn)行反序列化。

(2)若User類(lèi)僅僅實(shí)現(xiàn)了Serializable接口,并且還定義了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),則采用以下方式進(jìn)行序列化與反序列化。

  •   ObjectOutputStream調(diào)用User對(duì)象的writeObject(ObjectOutputStream out)的方法進(jìn)行序列化。
  •   ObjectInputStream會(huì)調(diào)用User對(duì)象的readObject(ObjectInputStream in)的方法進(jìn)行反序列化。

(3)若User類(lèi)實(shí)現(xiàn)了Externalnalizable接口,且User類(lèi)必須實(shí)現(xiàn)readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,則按照以下方式進(jìn)行序列化與反序列化。

  •   ObjectOutputStream調(diào)用User對(duì)象的writeExternal(ObjectOutput out))的方法進(jìn)行序列化。
  •   ObjectInputStream會(huì)調(diào)用User對(duì)象的readExternal(ObjectInput in)的方法進(jìn)行反序列化。

4、JDK類(lèi)庫(kù)中序列化的步驟

步驟一:創(chuàng)建一個(gè)對(duì)象輸出流,它可以包裝一個(gè)其它類(lèi)型的目標(biāo)輸出流,如文件輸出流:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\object.out"));

步驟二:通過(guò)對(duì)象輸出流的writeObject()方法寫(xiě)對(duì)象:

oos.writeObject(new User("xuliugen", "123456", "male"));

5、JDK類(lèi)庫(kù)中反序列化的步驟

步驟一:創(chuàng)建一個(gè)對(duì)象輸入流,它可以包裝一個(gè)其它類(lèi)型輸入流,如文件輸入流:

ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));

步驟二:通過(guò)對(duì)象輸出流的readObject()方法讀取對(duì)象:

User user = (User) ois.readObject();

說(shuō)明:為了正確讀取數(shù)據(jù),完成反序列化,必須保證向?qū)ο筝敵隽鲗?xiě)對(duì)象的順序與從對(duì)象輸入流中讀對(duì)象的順序一致。

6、序列化和反序列化的示例

為了更好地理解Java序列化與反序列化,舉一個(gè)簡(jiǎn)單的示例如下:

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打開(kāi)):

注:上圖中0000000h-000000c0h表示行號(hào);0-f表示列;行后面的文字表示對(duì)這行16進(jìn)制的解釋;對(duì)上述字節(jié)碼所表述的內(nèi)容感興趣的可以對(duì)照相關(guān)的資料,查閱一下每一個(gè)字符代表的含義,這里不在探討!

  類(lèi)似于我們Java代碼編譯之后的.class文件,每一個(gè)字符都代表一定的含義。序列化和反序列化的過(guò)程就是生成和解析上述字符的過(guò)程!

序列化圖示:

反序列化圖示:

三、相關(guān)注意事項(xiàng)

 1、序列化時(shí),只對(duì)對(duì)象的狀態(tài)進(jìn)行保存,而不管對(duì)象的方法;

 2、當(dāng)一個(gè)父類(lèi)實(shí)現(xiàn)序列化,子類(lèi)自動(dòng)實(shí)現(xiàn)序列化,不需要顯式實(shí)現(xiàn)Serializable接口;

 3、當(dāng)一個(gè)對(duì)象的實(shí)例變量引用其他對(duì)象,序列化該對(duì)象時(shí)也把引用對(duì)象進(jìn)行序列化;

 4、并非所有的對(duì)象都可以序列化,至于為什么不可以,有很多原因了,比如:

  安全方面的原因,比如一個(gè)對(duì)象擁有private,public等f(wàn)ield,對(duì)于一個(gè)要傳輸?shù)膶?duì)象,比如寫(xiě)到文件,或者進(jìn)行RMI傳輸?shù)鹊龋谛蛄谢M(jìn)行傳輸?shù)倪^(guò)程中,這個(gè)對(duì)象的private等域是不受保護(hù)的;

  資源分配方面的原因,比如socket,thread類(lèi),如果可以序列化,進(jìn)行傳輸或者保存,也無(wú)法對(duì)他們進(jìn)行重新的資源分配,而且,也是沒(méi)有必要這樣實(shí)現(xiàn);

 5、聲明為static和transient類(lèi)型的成員數(shù)據(jù)不能被序列化。因?yàn)閟tatic代表類(lèi)的狀態(tài),transient代表對(duì)象的臨時(shí)數(shù)據(jù)。

 6、序列化運(yùn)行時(shí)使用一個(gè)稱為 serialVersionUID 的版本號(hào)與每個(gè)可序列化類(lèi)相關(guān)聯(lián),該序列號(hào)在反序列化過(guò)程中用于驗(yàn)證序列化對(duì)象的發(fā)送者和接收者是否為該對(duì)象加載了與序列化兼容的類(lèi)。為它賦予明確的值。顯式地定義serialVersionUID有兩種用途:

  在某些場(chǎng)合,希望類(lèi)的不同版本對(duì)序列化兼容,因此需要確保類(lèi)的不同版本具有相同的serialVersionUID;

  在某些場(chǎng)合,不希望類(lèi)的不同版本對(duì)序列化兼容,因此需要確保類(lèi)的不同版本具有不同的serialVersionUID。

 7、Java有很多基礎(chǔ)類(lèi)已經(jīng)實(shí)現(xiàn)了serializable接口,比如String,Vector等。但是也有一些沒(méi)有實(shí)現(xiàn)serializable接口的;

 8、如果一個(gè)對(duì)象的成員變量是一個(gè)對(duì)象,那么這個(gè)對(duì)象的數(shù)據(jù)成員也會(huì)被保存!這是能用序列化解決深拷貝的重要原因;

四、反序列化漏洞

相關(guān)反序列化漏洞可以查閱相關(guān)資料,這里不介紹了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java反射的使用和原理詳解

    Java反射的使用和原理詳解

    這篇文章主要介紹了Java反射的使用和原理詳解,反射是java語(yǔ)言的一個(gè)特性,它允程序在運(yùn)行時(shí)(注意不是編譯的時(shí)候)來(lái)進(jìn)行自我檢查并且對(duì)內(nèi)部的成員進(jìn)行操作,需要的朋友可以參考下
    2024-01-01
  • Kotlin 語(yǔ)言中調(diào)用 JavaScript 方法實(shí)例詳解

    Kotlin 語(yǔ)言中調(diào)用 JavaScript 方法實(shí)例詳解

    這篇文章主要介紹了Kotlin 語(yǔ)言中調(diào)用 JavaScript 方法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • SpringBoot導(dǎo)入Druid運(yùn)行失敗問(wèn)題

    SpringBoot導(dǎo)入Druid運(yùn)行失敗問(wèn)題

    這篇文章主要介紹了SpringBoot導(dǎo)入Druid運(yùn)行失敗,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • JavaWeb文件上傳開(kāi)發(fā)實(shí)例

    JavaWeb文件上傳開(kāi)發(fā)實(shí)例

    這篇文章主要為大家詳細(xì)介紹了JavaWeb文件上傳開(kāi)發(fā)實(shí)例,如何進(jìn)行文件上傳操作,感興趣的小伙伴們可以參考一下
    2016-08-08
  • SpringMvc/SpringBoot HTTP通信加解密的實(shí)現(xiàn)

    SpringMvc/SpringBoot HTTP通信加解密的實(shí)現(xiàn)

    這篇文章主要介紹了SpringMvc/SpringBoot HTTP通信加解密的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 關(guān)于弗洛伊德算法求最短路徑詳解

    關(guān)于弗洛伊德算法求最短路徑詳解

    這篇文章主要介紹了關(guān)于弗洛伊德算法求最短路徑詳解,弗洛伊德算法VS迪杰斯特拉算法:迪杰斯特拉算法通過(guò)選定的被訪問(wèn)頂點(diǎn),求出從出發(fā)訪問(wèn)頂點(diǎn)到其他項(xiàng)點(diǎn)的最短路徑:弗洛伊德算法中每-個(gè)頂點(diǎn)都是出發(fā)訪問(wèn)點(diǎn),需要的朋友可以參考下
    2023-07-07
  • java的==運(yùn)算符和equals操作詳解

    java的==運(yùn)算符和equals操作詳解

    在Java中,==和equals都是用于比較兩個(gè)對(duì)象的操作符,但它們的行為和用途有所不同,這篇文章主要介紹了java的==運(yùn)算符和equals的相關(guān)知識(shí),需要的朋友可以參考下
    2024-08-08
  • Java排序算法總結(jié)之插入排序

    Java排序算法總結(jié)之插入排序

    這篇文章主要介紹了Java排序算法總結(jié)之插入排序,較為詳細(xì)的分析了插入排序的原理與java實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-05-05
  • JAVA8 lambda表達(dá)式權(quán)威教程

    JAVA8 lambda表達(dá)式權(quán)威教程

    本文主要給大家講解Java8中最重要的一個(gè)特征之一lambda表達(dá)式,本文通過(guò)實(shí)例圖文解說(shuō)給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友跟隨小編一起學(xué)習(xí)下吧
    2021-05-05
  • SpringJPA?做分頁(yè)條件查詢的代碼實(shí)踐

    SpringJPA?做分頁(yè)條件查詢的代碼實(shí)踐

    相信小伙伴們的項(xiàng)目很多都用到SpringJPA框架的吧,對(duì)于單表的增刪改查利用jpa是很方便的,但是對(duì)于條件查詢并且分頁(yè)?是不是很多小伙伴不經(jīng)常寫(xiě)到,今天給大家分享SpringJPA?做分頁(yè)條件查詢的案例代碼,感興趣的朋友一起看看吧
    2024-03-03

最新評(píng)論

定南县| 新津县| 林西县| 苏尼特左旗| 泾川县| 屏边| 石柱| 毕节市| 新龙县| 城口县| 汕尾市| 萨嘎县| 鄂州市| 安宁市| 贵阳市| 张家港市| 周口市| 磐石市| 阳江市| 台南县| 江安县| 邳州市| 南华县| 古田县| 海安县| 乃东县| 吴忠市| 紫金县| 佛学| 临洮县| 郎溪县| 丘北县| 内丘县| 莱芜市| 泸西县| 太保市| 永和县| 安达市| 东平县| 车致| 扶余县|