首頁 > 軟體

一文詳解Java物件的序列化和反序列化

2023-11-22 14:00:33

Java 物件的序列化和反序列化是一種將物件轉換成位元組流並儲存在硬碟或網路中,以及從位元組流中重新載入物件的操作。Java 的序列化和反序列化提供了一種方便的方式,使得可以將物件在不同的應用程式之間進行互動。

一、什麼是 Java 序列化和反序列化?

Java 物件的序列化是將 Java 物件轉換成位元組流的過程,可用於持久化資料,傳輸資料等。序列化是將 Java 物件的狀態表示為位元組序列的過程,可以通過網路傳送,儲存到檔案中或者使用其他的持久化技術,如資料庫等。序列化後的位元組流可以被傳輸給遠端系統,並在那裡重新構造成原始物件。Java 序列化是一個將物件轉化為位元組流的過程。

Java 物件的反序列化是將位元組流重新恢復為原始物件的過程。反序列化是將位元組流轉化為物件的過程。反序列化是物件序列化的逆過程,通過反序列化操作能夠在接收端恢復出與傳送端相同的物件。當我們需要對儲存的物件進行讀取操作時,就需要對序列化的位元組流進行反序列化操作,將位元組流轉化為原始的物件資訊。

二、序列化和反序列化的實現方式

Java 中的序列化和反序列化可以通過實現 Serializable 介面來完成。Serializable 是一種標記介面,它沒有方法定義,但它具有一個特別的作用,就是用於在描述 java 類可序列化時做型別判斷的資訊。當一個類實現 Serializable 介面時,表明這個類是可序列化的。Serializable 介面只是一個標識介面,我們並不需要過載任何方法。

在實現 Serializable 介面後,就可以通過 ObjectOutputStream 來將物件序列化,並將序列化後的位元組流輸出到檔案或網路中;同時,也可以通過 ObjectInputStream 來將序列化後的位元組流反序列化成物件。 java.io.ObjectOutputStream 繼承自 OutputStream 類,因此可以將序列化後的位元組序列寫入到檔案、網路等輸出流中。

來看 ObjectOutputStream 的構造方法: ObjectOutputStream(OutputStream out)

一個物件要想序列化,必須滿足兩個條件:

  • 該類必須實現java.io.Serializable 介面open in new window,否則會丟擲NotSerializableException 。
  • 該類的所有欄位都必須是可序列化的。如果一個欄位不需要序列化,則需要使用transient 關鍵字open in new window進行修飾。
  • 該構造方法接收一個 OutputStream 物件作為引數,用於將序列化後的位元組序列輸出到指定的輸出流中。

範例程式碼如下:

import java.io.*;

public class SerializationDemo {
    public static void main(String[] args) {
        // 序列化物件
        Person person = new Person("Tom", 20);
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("person.txt"));
            objectOutputStream.writeObject(person);
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化物件
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("person.txt"));
            Person restoredPerson = (Person) objectInputStream.readObject();
            System.out.println(restoredPerson);
            objectInputStream.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

在上述程式碼中,我們定義了一個 Person 類,該類實現了 Serializable 介面。在序列化過程中,我們使用 ObjectOutputStream 類將 person 物件寫出到檔案中;在反序列化過程中,我們使用 ObjectInputStream 類讀取檔案中的位元組流,並將其轉換為 Person 物件。

三、序列化和反序列化的注意事項

  • 私有化序列號屬性

序列化和反序列化需要使用物件的序列號屬性(serialVersionUID)來判斷版本號是否一致,從而防止在新版本和舊版本之間發生不相容的情況。如果沒有顯式地宣告 serialVersionUID,則編譯器會自動生成一個 serialVersionUID,但這種方式是不可靠的,因為在修改過程中可能會產生 serialVersionUID 的變化,從而導致不相容問題。

因此,在 Java 序列化中,最好顯式地宣告 serialVersionUID 屬性,並進行私有化,避免意外的修改。例如:

private static final long serialVersionUID = 1L;
  • 實現 readObject 和 writeObject 方法

readObject 和 writeObject 是在序列化和反序列化過程中用於自定義序列化的方法。通常情況下,我們可以直接使用預設的序列化方法,但是有時我們需要對序列化內容進行一些處理,這時就需要實現 readObject 和 writeObject 方法。例如,對於物件中敏感資料的處理,我們可以在 writeObject 方法中對資料進行加密處理,在 readObject 方法中解密處理。

需要注意的是,在實現 readObject 和 writeObject 方法時,必須要呼叫預設方法,預設方法可以通過 ObjectInputStream 和 ObjectOutputStream 類的 defaultReadObject 和 defaultWriteObject 方法呼叫。

四、序列化和反序列化的優點和缺點

序列化和反序列化的優點是:

  • 物件的序列化方便了物件在不同應用之間的傳遞、儲存和恢復。

  • 通過序列化可以實現分散式計算,在不同的機器上對同一物件進行操作和共同作業。

  • 序列化提供了資料持久化的能力,即將物件的狀態儲存在硬碟等媒介中,下次可以直接從硬碟中讀取資料,避免了頻繁地進行資料庫讀寫操作。

序列化和反序列化的缺點是:

  • 在進行序列化和反序列化操作時,需要消耗額外的時間和開銷,特別是當物件比較大或者巢狀較深的時候,可能會導致嚴重的效能問題。

  • 序列化和反序列化可能存在安全性問題,如果被攻擊者篡改了序列化後的位元組流資料,那麼反序列化後的物件可能會出現意外行為,如獲得不應該獲得的許可權。

五、總結

Java 物件的序列化和反序列化是一種將物件轉換成位元組流並儲存在硬碟或網路中,以及從位元組流中重新載入物件的操作。序列化和反序列化均需要實現 Serializable 介面,並使用 ObjectOutputStream 和 ObjectInputStream 類來完成。序列化和反序列化可以方便地實現物件在不同應用之間的傳遞、儲存和恢復等功能,但也存在一些缺點,如可能會導致嚴重的效能問題和安全性問題。在使用過程中,需要根據具體的業務場景和需求進行選擇和優化,以達到最佳的效果。

在實際的 Java 開發中,序列化和反序列化是一個非常常見的操作,例如在分散式系統中,需要將物件序列化後通過網路傳輸,在不同的機器上進行反序列化以得到原始物件。

以下是一些使用序列化和反序列化的範例場景:

  • 快取

在實際的開發中,我們經常需要對一些資料進行快取,使用序列化可以將物件序列化為位元組陣列,然後將位元組陣列儲存到檔案或者快取中。當需要使用快取中的物件時,再進行反序列化操作,重新獲得原始物件。

  • 遠端呼叫

在分散式系統中,需要將物件序列化後通過網路傳輸,在不同的機器上進行反序列化以得到原始物件。例如在 Dubbo 框架中,就使用了物件序列化和反序列化機制。

  • 持久化資料

在實際的開發中,我們需要將某些物件的狀態儲存到資料庫或者檔案中,使用序列化可以將物件序列化為位元組陣列,然後將位元組陣列儲存到資料庫或者檔案中。當需要讀取資料時,再進行反序列化操作,獲得原始物件。

一般使用 Java 序列化和反序列化只需要實現 Serializable 介面即可,但是也可以使用一些工具依賴來簡化操作。以下是一些常用的序列化和反序列化工具依賴:

1. Jackson

Jackson 是一個非常常用的序列化和反序列化工具,在 Spring Boot 等框架中也被廣泛使用。Jackson 可以將物件序列化為 JSON 或者 XML 格式,同時也可以將 JSON 或者 XML 反序列化為物件。

2. Gson

Gson 是另一個常用的序列化和反序列化工具,同樣可以將物件序列化為 JSON 格式,也可以將 JSON 反序列化為物件。

3. Protobuf

Protobuf 是 Google 開源的一種輕量級、高效、可延伸的序列化框架,支援多種程式語言。與 Java 序列化相比,Protobuf 使用效率更高,序列化後的位元組流更小,但需要預定義訊息格式。

4. Kyro

Kryo 是一個高效能的 Java 序列化和反序列化工具,可以將 Java 物件序列化為位元組陣列,適合於網路通訊和資料持久化等場景。Kryo 能夠快速地序列化和反序列化 Java 物件,相對於 Java 自帶的序列化機制,它的速度更快,序列化後的位元組陣列也更小。

以上是一些常用的序列化和反序列化工具依賴,根據不同的業務需求和場景需要選擇適合的工具。

到此這篇關於一文詳解Java物件的序列化和反序列化的文章就介紹到這了,更多相關Java物件的序列化和反序列化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com