Java 序列化與反序列化

来源:http://www.cnblogs.com/jaycekon/archive/2016/10/28/6009498.html
-Advertisement-
Play Games

1、什麼是序列化?為什麼要序列化? Java 序列化就是指將對象轉換為位元組序列的過程,而反序列化則是只將位元組序列轉換成目標對象的過程。 我們都知道,在進行瀏覽器訪問的時候,我們看到的文本、圖片、音頻、視頻等都是通過二進位序列進行傳輸的,那麼如果我們需要將Java對象進行傳輸的時候,是不是也應該先將對 ...


1、什麼是序列化?為什麼要序列化?

    Java 序列化就是指將對象轉換為位元組序列的過程,而反序列化則是只將位元組序列轉換成目標對象的過程。

    我們都知道,在進行瀏覽器訪問的時候,我們看到的文本、圖片、音頻、視頻等都是通過二進位序列進行傳輸的,那麼如果我們需要將Java對象進行傳輸的時候,是不是也應該先將對象進行序列化?答案是肯定的,我們需要先將Java對象進行序列化,然後通過網路,IO進行傳輸,當到達目的地之後,再進行反序列化獲取到我們想要的對象,最後完成通信。

 

2、如何實現序列化

  2.1、使用到JDK中關鍵類 ObjectOutputStream 和ObjectInputStream

    ObjectOutputStream 類中:通過使用writeObject(Object object) 方法,將對象以二進位格式進行寫入。

    ObjectInputStream 類中:通過使用readObject()方法,從輸入流中讀取二進位流,轉換成對象。

 

  2.2、目標對象需要先實現 Seriable介面

  

我們創建一個Student類:

public class Student implements Serializable {
    private static final long serialVersionUID = 3404072173323892464L;
    private String name;
    private transient String id;
    private String age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public Student(String name, String id) {
        System.out.println("args Constructor");
        this.name = name;
        this.id = id;
    }

    public Student() {
        System.out.println("none-arg Constructor");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

 

        

      代碼中Student類實現了Serializable 介面,並且生成了一個版本號:

private static final long serialVersionUID = 3404072173323892464L;

      首先:

      1、Serializable 介面的作用只是用來標識我們這個類是需要進行序列化,並且Serializable 介面中並沒有提供任何方法。

      2、serialVersionUid 序列化版本號的作用是用來區分我們所編寫的類的版本,用於判斷反序列化時類的版本是否一直,如果不一致會出現版本不一致異常。

      3、transient 關鍵字,主要用來忽略我們不希望進行序列化的變數

 

    2.3、將對象進行序列或和反序列化

      2.3.1 第一種寫入方式:

public static  void main(String[] args){
        File file = new File("D:/test.txt");
        Student student = new Student("孫悟空","12");
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
            outputStream.writeObject(student);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            Student s = (Student) objectInputStream.readObject();
            System.out.println(s.toString());
            System.out.println(s.equals(student));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

      創建對象Student ,然後通過ObjectOutputStream類中的writeObject()方法,將對象輸出到文件中。

      然後通過ObjectinputStream 類中的readObject()方法反序列化,獲取對象。

 

       2.3.2 第二種寫入方式:

在Student 類中實現writeObject()和readObject()方法:

  private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
        objectOutputStream.defaultWriteObject();
        objectOutputStream.writeUTF(id);

    }

    private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
        objectInputStream.defaultReadObject();
        id = objectInputStream.readUTF();
    }

      通過這中方式進行序列話,我們可以自定義想要進行序列化的變數,將輸入流和輸出流傳入對線實例中,然後進行序列化以及反序列化。

  

      2.3.3 第三種寫入方式:

Student 實現 Externalnalizable介面 而不實現Serializable 介面

 Externaliable 介面是 Serializable 的子類,有著和Serializable介面同樣的功能:

public class Student implements Externalizable {
    private static final long serialVersionUID = 3404072173323892464L;
    private String name;
    private transient String id;
    private String age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public Student(String name, String id) {
        System.out.println("args Constructor");
        this.name = name;
        this.id = id;
    }

    public Student() {
        System.out.println("none-arg Constructor");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }


    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeObject(id);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        id = (String) in .readObject();
    }

}

 

   通過和前面的第二種寫入方法對比,我們可以發現他們的實現原理都是十分的類似,不過實現Externalnalizable介面 並不支持第一種序列化方法,它只能夠通過實現介面中的writeExternal()和readExternal()方法實現對象的序列化。

 

 

3、面試中關於序列化的問題:

    1、什麼是序列化,如何實現序列化

        java中對象的序列化就是將對象轉換成二進位序列,反序列化則是將二進位序列轉換成對象

        Java 實現序列化有多種方式

          1、首先需要使用到工具類ObjectInputStream 和ObjectOutputStream 兩個IO類

          2、實現Serializable 介面:

              有兩種具體序列化方法:

                  2.1 直接通過ObjectOutputStream 和 ObjectInputStream 類中的 writeObject()和readObject()方法

                  2.2 通過在序列化對象中實現writeObject()和readObject()方法,傳入ObjectOutputStream和ObjectInputStream對象,完成序列化

          3、實現Externalizable 介面:

                  只能夠通過實現介面中的writeExternal()和readExternal()方法實現對象的序列化


     2、transient 關鍵字?如何將transient修飾符修飾的變數序列化?
        
transient 的作用是用來屏蔽我們不希望進行序列化的變數,是對象在進行序列化和反序列話的過程中忽略該變數。
        我們可以通過上述序列化方法中的 實現writeObject 和readObject 方法,在方法中調用輸出流或輸入流的writeUTF()和readUTF()方法。
        或者通過實現Externalizable 介面,實現writeExternal()和readExternal()方法,然後再自定義序列話對象。

     
      3、如何保證序列化和反序列化後的對象一致?(如有異議望指正)
       
 對於這個問題我在查閱了一些資料之後,發現並不能保證序列化和反序列化之後的對象是一致的,因為我們在反序列化的過程中,是先創建一個對象,
        然後再通過對對象進行賦值來完成對象的反序列化,這樣問題就來了,在創建了一個新的對象之後,對象引用和原本的對象並不是指向同一個目標。
        因此我們只能保證他們的數據和版本一致,並不能保證對象一致。

 

  

    


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 英文文檔: ...
  • 本文通過從無到有創建一個利用Go語言實現的非常簡單的HttpServer,來讓大家熟悉利用Go語言時的基本流程,工具和代碼的基本佈局,為學習Go語言時碰到的環境問題掃清障礙。 ...
  • 1. 設置軟體斷點,運行到目標位置啟動調試器 方法①:使用彙編指令(註:x64 c++不支持彙編) 方法②:編譯器提供的方法 方法③:使用windows API WerFault.exe進程(Windows Error Reporting)彈出ConsoleTest.exe已停止工作: 要想出現“調 ...
  • Google Glog 是一個C++語言的應用級日誌記錄框架,提供了 C++ 風格的流操作和各種助手巨集。試用了一下,感覺不錯,試用過程出了不少插曲。 1、開源項目首頁已經從https://code.google.com/p/google-glog/遷移到https://github.com/goog ...
  • 在java中,當對象不存在任何引用的時候,它就成為了垃圾,如果不及時回收,釋放記憶體,垃圾便會越積越多,最終out of memory!,jvm也就結束運行了。 有人疑惑了:我們平時編碼時並沒有顯示的進行對象的銷毀,怎麼程式跑的好好的? 這就要談到今天的主角,jvm的守護式線程GC,GC是一個垃圾回收 ...
  • 英文文檔: 2. 函數第三個參數default為可選參數,如果object中含義name屬性,則返回name屬性的值,如果沒有name屬性,則返回default值,如果default未傳入值,則報錯。 ...
  • 英文文檔: 2. 不傳入參數時,生成的空的不可變集合。 ...
  • JVM記憶體區域 我們在編寫程式時,經常會遇到OOM(out of Memory)以及記憶體泄漏等問題。為了避免出現這些問題,我們首先必須對JVM的記憶體劃分有個具體的認識。JVM將記憶體主要劃分為:方法區、虛擬機棧、本地方法棧、堆、程式計數器。JVM運行時數據區如下: 程式計數器 程式計數器是線程私有的區 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...