亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

圖文詳解Java中的序列化機制

 更新時間:2022年10月04日 09:14:21   作者:JAVA旭陽  
java中的序列化可能大家像我一樣都停留在實現(xiàn)Serializable接口上,對于它里面的一些核心機制沒有深入了解過。本文將通過示例帶大家深入了解Java中的序列化機制,需要的可以參考一下

概述

java中的序列化可能大家像我一樣都停留在實現(xiàn)Serializable接口上,對于它里面的一些核心機制沒有深入了解過。直到最近在項目中踩了一個坑,就是序列化對象添加一個字段以后,使用方系統(tǒng)報了反序列化失敗,原因是我們雙方的序列化對象沒有加上serialVersionUID,那你們知道下面幾個問題嗎:

  • 序列化對象中的serialVersionUID 是干嘛用的?
  • 如何修改默認的序列化機制?
  • 如何使用序列化的方式克隆對象?

對象序列化和反序列化機制

序列化: 將對象轉成二進制寫到輸出流的過程。

反序列化: 通過輸入流讀回二進制轉成對象的過程。

通過對象的序列化和反序列化機制可以實現(xiàn)對象在網絡之間傳輸。

在Java中,如果一個對象要想實現(xiàn)序列化,必須要實現(xiàn)下面兩個接口之一:

  • Serializable 接口
  • Externalizable 接口

這里我們先講解常用的Serializable 接口。

writeObject序列化過程栗子:

@Test
public void testSerializable() throws FileNotFoundException {
    User user = new User("alvin", 19);
    // 文件輸出流
    FileOutputStream bout = new FileOutputStream("user.dat");
    try (ObjectOutputStream out = new ObjectOutputStream(bout)) {
        // 序列化
        out.writeObject(user);
    } catch (IOException e) {
        e.printStackTrace();
    }
}


@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {

    private String username;

    private Integer age;
}

結果:

readObject反序列化栗子:

現(xiàn)在模擬另外一個系統(tǒng)需要反序列化user.dat

@Test
public void testDeSerializable() throws FileNotFoundException {
    User user = null;
    // 寫到內存中,當然也可以寫到文件中
    FileInputStream fis = new FileInputStream("user.dat");
    try (ObjectInputStream in = new ObjectInputStream(fis)) {
        // 反序列化 readObject
        user = (User) in.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }

    Assert.assertEquals("alvin", user.getUsername());
}

如果User類不實現(xiàn)Serializable接口, 那會怎么樣?

當然是報錯了,如下圖:

小結:

一個對象想要被序列化,那么它的類就要實現(xiàn)此接口或者它的子接口。

修改默認的序列化機制

默認的情況下,如果實現(xiàn)了Serializable接口的對象進行序列化的時候,默認會將全部的數據域,也就是成員變量進行序列化輸出,那往往有時候并不需要這樣,有什么方法可以修改序列化機制呢?下面提供3中方式。

使用transient關鍵字

將成員變量標記成transient,那么在序列化的過程中這些數據域會被跳過,如下圖所示:

這是一種最簡單的方式,但是不夠靈活。

自定義readObject、writeObject方法

序列化類中可以通過定義下面簽名的方法:

  • private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException
  • private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException

只要類中有這兩個簽名的方法,那么就不會調用默認的序列化,取而代之調用這些方法。

本例我們舉個jdk中的例子,ArrayList就實現(xiàn)了這兩個方法,重寫了序列化機制。

主要原因ArrayList底層的數組通常會預留一些容量,等容量不足時再擴充容量,那么有些空間可能就沒有實際存儲元素,采用自定義方式實現(xiàn)序列化時,就可以保證只序列化實際存儲的那些元素,而不是整個數組,從而節(jié)省空間和時間。

實現(xiàn)Externalizable接口

Externalizable接口想必大家很少用到,它是Serializable接口的子類,用戶要實現(xiàn)的writeExternal()和readExternal() 方法,用來決定如何序列化和反序列化。

因為序列化和反序列化方法需要自己實現(xiàn),因此可以指定序列化哪些屬性,而transient在這里無效。

對Externalizable對象反序列化時,會先調用類的無參構造方法,這是有別于默認反序列方式的。如果把類的不帶參數的構造方法刪除,或者把該構造方法的訪問權限設置為private、默認或protected級別,會拋出java.io.InvalidException: no valid constructor異常,因此Externalizable對象必須有默認構造函數,而且必需是public的。

舉例說明:

public class User2 implements Externalizable {

    private String username;

    private Integer age;

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(username);
        out.writeInt(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        username = in.readUTF();
        age = in.readInt();
    }
}

serialVersionUID的作用

這就回到概述中提到的項目中遇到的問題,現(xiàn)在簡要描述下:

A系統(tǒng)中的序列化對象User用的最新版本如下:

B系統(tǒng)中反序列化的對象,還是老的User版本如下:

這時候A系統(tǒng)生成的序列化文件,交給B系統(tǒng)反序列化時,出錯了, 如下圖:

原因:

類定義發(fā)生了變化,比如添加、刪除、修改類中的數據域后,它的唯一標記符或者稱為SHA指紋、或者理解為serialVersionUID都會發(fā)生變化,這個值會保存在序列化二進制中,如果反序列化過程發(fā)現(xiàn)對不上,就會報錯,如上圖所示。

那么如何處理呢?

這時候,我們如果覺得這個序列化對象是可以兼容的,那么可以自定義一個serialVersionUID的靜態(tài)成員變量,它就不會自動生成,而是直接用這個值,如下圖:

使用序列化clone

clone大家都知道吧,在深拷貝的時候編碼還是很麻煩的,借用序列化機制可以實現(xiàn)深拷貝。做法很簡單,就是將對象序列化到輸出流中,然后讀回。

public class SerialCloneable implements Cloneable, Serializable {

    @Override
    public Object clone() throws CloneNotSupportedException {
        try {
            // 保存到字節(jié)數組流
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            try(ObjectOutputStream out = new ObjectOutputStream(bout)) {
                out.writeObject(this);
            }
            // 讀取
            try(InputStream bin = new ByteArrayInputStream(bout.toByteArray())) {
                ObjectInputStream in = new ObjectInputStream(bin);
                return in.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
            CloneNotSupportedException e2 = new CloneNotSupportedException();
            e2.initCause(e);
            throw e2;
        }
    }
}

注意一點,這種方式性能不高,通常比顯示構建、復制數據要慢不少。

到此這篇關于圖文詳解Java中的序列化機制的文章就介紹到這了,更多相關Java序列化機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java使用jni清屏功能的實現(xiàn)(只針對cmd)

    Java使用jni清屏功能的實現(xiàn)(只針對cmd)

    JNI是Java Native Interface的縮寫,它提供了若干的API實現(xiàn)了Java和其他語言的通信(主要是C&C++)。這篇文章主要介紹了Java使用jni清屏功能的實現(xiàn)(只針對cmd) ,感興趣的朋友跟隨腳本之家小編一起學習吧
    2018-05-05
  • maven導入無法拉取所需依賴的解決方法

    maven導入無法拉取所需依賴的解決方法

    最近遇到個問題maven導入無法拉取所需依賴的解決方法,本文就來詳細的介紹一下解決方法,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2024-02-02
  • java求數組元素重復次數和java字符串比較大小示例

    java求數組元素重復次數和java字符串比較大小示例

    這篇文章主要介紹了java求數組元素重復次數和java字符串比較大小示例,需要的朋友可以參考下
    2014-04-04
  • 如何用Java將數據庫的數據生成pdf返回給前端用戶下載

    如何用Java將數據庫的數據生成pdf返回給前端用戶下載

    本文詳細介紹了使用SpringBoot、iText庫、MyBatis等技術從數據庫中選取數據并生成PDF文件的后端處理流程,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-09-09
  • java使用RabbitMQ實現(xiàn)延遲消息示例

    java使用RabbitMQ實現(xiàn)延遲消息示例

    本文介紹了在分布式系統(tǒng)中,使用RabbitMQ實現(xiàn)延遲消息處理,其中詳細闡述了RabbitMQ隊列和交換機的配置、消息的發(fā)送與接收以及死信隊列的處理,具有一定的參考價值,感興趣的可以了解一下
    2024-10-10
  • Java并發(fā)編程之ConcurrentLinkedQueue隊列詳情

    Java并發(fā)編程之ConcurrentLinkedQueue隊列詳情

    這篇文章主要介紹了Java并發(fā)編程之ConcurrentLinkedQueue隊列詳情,ConcurrentLinkedQueue?內部的隊列使用單向鏈表方式實現(xiàn),下文更多相關內容敘述需要的小伙伴可以參考一下
    2022-04-04
  • Java中scheduleAtFixedRate的用法

    Java中scheduleAtFixedRate的用法

    如何正確使用Java中的scheduleAtFixedRate是一篇介紹Java中定時任務調度器的文章。它詳細介紹了scheduleAtFixedRate方法的用法、參數及作用,并給出了一些實例以幫助讀者更好地理解其使用。本文為Java開發(fā)人員提供了一些實用的技巧,幫助他們更好地管理和控制定時任務
    2023-04-04
  • idea項目的左側目錄沒了如何設置

    idea項目的左側目錄沒了如何設置

    這篇文章主要介紹了idea項目的左側目錄沒了如何設置的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • java 多態(tài)實例代碼

    java 多態(tài)實例代碼

    這篇文章主要介紹了java 多態(tài)實例代碼,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • Spring?Cloud實現(xiàn)灰度發(fā)布的示例代碼

    Spring?Cloud實現(xiàn)灰度發(fā)布的示例代碼

    這篇文章主要為大家詳細介紹了Spring?Cloud實現(xiàn)灰度發(fā)布的相關知識,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解一下
    2023-09-09

最新評論