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

JAVA序列化和反序列化的底層實現原理解析

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

一、基本概念

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

?。?)Java序列化是指把Java對象轉換為字節(jié)序列的過程,而Java反序列化是指把字節(jié)序列恢復為Java對象的過程;

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

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

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

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

  我們知道,當兩個進程進行遠程通信時,可以相互發(fā)送各種類型的數據,包括文本、圖片、音頻、視頻等, 而這些數據都會以二進制序列的形式在網絡上傳送。

  那么當兩個Java進程進行通信時,能否實現進程間的對象傳送呢?答案是可以的!如何做到呢?這就需要Java序列化與反序列化了!

  換句話說,一方面,發(fā)送方需要把這個Java對象轉換為字節(jié)序列,然后在網絡上傳送;另一方面,接收方需要從字節(jié)序列中恢復出Java對象。

  當我們明晰了為什么需要Java序列化和反序列化后,我們很自然地會想Java序列化的好處。其好處一是實現了數據的持久化,通過序列化可以把數據永久地保存到硬盤上(通常存放在文件里),二是,利用序列化實現遠程通信,即在網絡上傳送對象的字節(jié)序列。

總的來說可以歸結為以下幾點:

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

(2)通過序列化以字節(jié)流的形式使對象在網絡中進行傳遞和接收;

(3)通過序列化在進程間傳遞對象;

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

(1)將對象實例相關的類元數據輸出。

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

(3)類元數據完了以后,開始從最頂層的超類開始輸出對象實例的實際數據值。

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

二、Java如何實現序列化和反序列化

1、JDK類庫中序列化和反序列化API

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

  它的writeObject(Object obj)方法可以對參數指定的obj對象進行序列化,把得到的字節(jié)序列寫到一個目標輸出流中;

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

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

2、實現序列化的要求

  只有實現了Serializable或Externalizable接口的類的對象才能被序列化,否則拋出異常!

3、實現Java對象序列化與反序列化的方法

假定一個User類,它的對象需要序列化,可以有如下三種方法:

(1)若User類僅僅實現了Serializable接口,則可以按照以下方式進行序列化和反序列化

  •   ObjectOutputStream采用默認的序列化方式,對User對象的非transient的實例變量進行序列化。
  •   ObjcetInputStream采用默認的反序列化方式,對對User對象的非transient的實例變量進行反序列化。

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

  •   ObjectOutputStream調用User對象的writeObject(ObjectOutputStream out)的方法進行序列化。
  •   ObjectInputStream會調用User對象的readObject(ObjectInputStream in)的方法進行反序列化。

(3)若User類實現了Externalnalizable接口,且User類必須實現readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,則按照以下方式進行序列化與反序列化。

  •   ObjectOutputStream調用User對象的writeExternal(ObjectOutput out))的方法進行序列化。
  •   ObjectInputStream會調用User對象的readExternal(ObjectInput in)的方法進行反序列化。

4、JDK類庫中序列化的步驟

步驟一:創(chuàng)建一個對象輸出流,它可以包裝一個其它類型的目標輸出流,如文件輸出流:

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

步驟二:通過對象輸出流的writeObject()方法寫對象:

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

5、JDK類庫中反序列化的步驟

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

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

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

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

說明:為了正確讀取數據,完成反序列化,必須保證向對象輸出流寫對象的順序與從對象輸入流中讀對象的順序一致。

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

為了更好地理解Java序列化與反序列化,舉一個簡單的示例如下:

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());
    //反序列化的輸出結果為:xuliugen 123456 male
  }
}

public class User implements Serializable {
  private String userName;
  private String password;
  private String sex;
  //全參構造方法、get和set方法省略
}

object.out文件如下(使用UltraEdit打開):

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

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

序列化圖示:

反序列化圖示:

三、相關注意事項

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

 2、當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable接口;

 3、當一個對象的實例變量引用其他對象,序列化該對象時也把引用對象進行序列化;

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

  安全方面的原因,比如一個對象擁有private,public等field,對于一個要傳輸的對象,比如寫到文件,或者進行RMI傳輸等等,在序列化進行傳輸的過程中,這個對象的private等域是不受保護的;

  資源分配方面的原因,比如socket,thread類,如果可以序列化,進行傳輸或者保存,也無法對他們進行重新的資源分配,而且,也是沒有必要這樣實現;

 5、聲明為static和transient類型的成員數據不能被序列化。因為static代表類的狀態(tài),transient代表對象的臨時數據。

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

  在某些場合,希望類的不同版本對序列化兼容,因此需要確保類的不同版本具有相同的serialVersionUID;

  在某些場合,不希望類的不同版本對序列化兼容,因此需要確保類的不同版本具有不同的serialVersionUID。

 7、Java有很多基礎類已經實現了serializable接口,比如String,Vector等。但是也有一些沒有實現serializable接口的;

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

四、反序列化漏洞

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

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

    Java反射的使用和原理詳解

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

    Kotlin 語言中調用 JavaScript 方法實例詳解

    這篇文章主要介紹了Kotlin 語言中調用 JavaScript 方法實例詳解的相關資料,需要的朋友可以參考下
    2017-06-06
  • SpringBoot導入Druid運行失敗問題

    SpringBoot導入Druid運行失敗問題

    這篇文章主要介紹了SpringBoot導入Druid運行失敗,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • JavaWeb文件上傳開發(fā)實例

    JavaWeb文件上傳開發(fā)實例

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

    SpringMvc/SpringBoot HTTP通信加解密的實現

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

    關于弗洛伊德算法求最短路徑詳解

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

    java的==運算符和equals操作詳解

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

    Java排序算法總結之插入排序

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

    JAVA8 lambda表達式權威教程

    本文主要給大家講解Java8中最重要的一個特征之一lambda表達式,本文通過實例圖文解說給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友跟隨小編一起學習下吧
    2021-05-05
  • SpringJPA?做分頁條件查詢的代碼實踐

    SpringJPA?做分頁條件查詢的代碼實踐

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

最新評論

宜兰县| 汉阴县| 太谷县| 北安市| 河源市| 金堂县| 海城市| 云南省| 瑞金市| 临沧市| 宁武县| 绩溪县| 自治县| 兴文县| 轮台县| 德庆县| 南阳市| 灵丘县| 莱州市| 乡城县| 哈密市| 安福县| 东明县| 邯郸县| 江西省| 潞西市| 健康| 黎城县| 青浦区| 明光市| 南安市| 广丰县| 济阳县| 松阳县| 新巴尔虎右旗| 青阳县| 望奎县| 繁昌县| 伊春市| 曲沃县| 会宁县|