欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中序列化與反序列化的特性解讀

 更新時(shí)間:2023年08月10日 09:21:27   作者:ycfxhsw  
這篇文章主要介紹了Java中序列化與反序列化的特性解讀,當(dāng)我們需要將內(nèi)存中的對(duì)象持久化到磁盤,數(shù)據(jù)庫中時(shí), 當(dāng)我們需要與瀏覽器進(jìn)行交互時(shí),當(dāng)我們需要實(shí)現(xiàn) RPC 時(shí), 這個(gè)時(shí)候就需要序列化和反序列化了,需要的朋友可以參考下

一、序列化與反序列化

  • 序列化:把對(duì)象轉(zhuǎn)換為字節(jié)序列的過程稱為對(duì)象的序列化。
  • 反序列化:把字節(jié)序列恢復(fù)為對(duì)象的過程稱為對(duì)象的反序列化。

二、什么時(shí)候需要用到序列化和反序列化

當(dāng)我們只在本地 JVM 里運(yùn)行下 Java 實(shí)例,這個(gè)時(shí)候是不需要什么序列化和反序列化的,但當(dāng)我們需要將內(nèi)存中的對(duì)象持久化到磁盤,數(shù)據(jù)庫中時(shí), 當(dāng)我們需要與瀏覽器進(jìn)行交互時(shí),當(dāng)我們需要實(shí)現(xiàn) RPC 時(shí), 這個(gè)時(shí)候就需要序列化和反序列化了。

前兩個(gè)需要用到序列化和反序列化的場(chǎng)景, 是不是讓我們有一個(gè)很大的疑問? 我們?cè)谂c瀏覽器交互時(shí),還有將內(nèi)存中的對(duì)象持久化到數(shù)據(jù)庫中時(shí),好像都沒有去進(jìn)行序列化和反序列化, 因?yàn)槲覀兌紱]有實(shí)現(xiàn) Serializable 接口, 但一直正常運(yùn)行。

下面先給出結(jié)論:

只要我們對(duì)內(nèi)存中的對(duì)象進(jìn)行持久化或網(wǎng)絡(luò)傳輸, 這個(gè)時(shí)候都需要序列化和反序列化.

理由:

服務(wù)器與瀏覽器交互時(shí)真的沒有用到 Serializable 接口嗎?JSON 格式實(shí)際上就是將一個(gè)對(duì)象轉(zhuǎn)化為字符串, 所以服務(wù)器與瀏覽器交互時(shí)的數(shù)據(jù)格式其實(shí)是字符串,我們來看來 String 類型的源碼:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

String 類型實(shí)現(xiàn)了 Serializable 接口,并顯示指定 serialVersionUID 的值.

然后我們?cè)賮砜磳?duì)象持久化到數(shù)據(jù)庫中時(shí)的情況, Mybatis 數(shù)據(jù)庫映射文件里的 insert 代碼:

<insert id="insertUser" parameterType="com.ycfxhsw.User">
    INSERT INTO t_user(name, age) VALUES (#{name}, #{age})
</insert>

實(shí)際上我們并不是將整個(gè)對(duì)象持久化到數(shù)據(jù)庫中, 而是將對(duì)象中的屬性持久化到數(shù)據(jù)庫中, 而這些屬性都是實(shí)現(xiàn)了 Serializable 接口的基本屬性.

三、為什么要實(shí)現(xiàn) Serializable 接口?

在 Java 中實(shí)現(xiàn)了 Serializable 接口后, JVM 會(huì)在底層幫我們實(shí)現(xiàn)序列化和反序列化, 如果我們不實(shí)現(xiàn) Serializable 接口, 那自己去寫一套序列化和反序列化代碼也行。

四、為什么還要指定 serialVersionUID 的值?

如果不顯示指定 serialVersionUID, JVM 在序列化時(shí)會(huì)根據(jù)屬性自動(dòng)生成一個(gè) serialVersionUID, 然后與屬性一起序列化,再進(jìn)行持久化或網(wǎng)絡(luò)傳輸。

在反序列化時(shí),JVM 會(huì)再根據(jù)屬性自動(dòng)生成一個(gè)新版 serialVersionUID,然后將這個(gè)新版 serialVersionUID 與序列化時(shí)生成的舊版 serialVersionUID 進(jìn)行比較,如果相同則反序列化成功, 否則報(bào)錯(cuò).

如果顯示指定了 serialVersionUID, JVM 在序列化和反序列化時(shí)仍然都會(huì)生成一個(gè) serialVersionUID, 但值為我們顯示指定的值,這樣在反序列化時(shí)新舊版本的 serialVersionUID 就一致了.

在實(shí)際開發(fā)中, 不顯示指定 serialVersionUID 的情況會(huì)導(dǎo)致什么問題?如果我們的類寫完后不再修改,那當(dāng)然不會(huì)有問題。

但這在實(shí)際開發(fā)中是不可能的,我們的類會(huì)不斷迭代,一旦類被修改了,那舊對(duì)象反序列化就會(huì)報(bào)錯(cuò)。所以在實(shí)際開發(fā)中, 我們都會(huì)顯示指定一個(gè) serialVersionUID,值是多少無所謂, 只要不變就行。

寫個(gè)實(shí)例測(cè)試下:

(1) User 類

  • 不顯示指定 serialVersionUID.
import java.io.Serializable;
public class User implements Serializable {
    String name;
    Integer age;
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
	// 省略 get/set 方法
}

(2) 測(cè)試類

先進(jìn)行序列化, 再進(jìn)行反序列化.

public class SerializeTest {
    private static File file = new File("D:/Desktop/user.txt");
    private static void serialize(User user) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(user);
        oos.close();
    }
    private static User deserialize() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        return (User) ois.readObject();
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User();
        user.setName("織女");
        user.setAge(18);
        System.out.println("序列化前的結(jié)果為:" + user);
        serialize(user);
        User user1 = deserialize();
        System.out.println("反序列化后的結(jié)果為:" + user1);
    }
}

序列化前的結(jié)果為:User{name=‘織女’, age=18}

反序列化后的結(jié)果為:User{name=‘織女’, age=18}

(3) 結(jié)果

先注釋掉反序列化代碼, 執(zhí)行序列化代碼, 然后 User 類新增一個(gè)屬性 sex

public class User implements Serializable {
    String name;
    Integer age;
    String sex;
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
	// // 省略 get/set 方法
}

再注釋掉序列化代碼執(zhí)行反序列化代碼, 最后結(jié)果如下:

local class incompatible: stream classdesc serialVersionUID = -8867211101605543804, local class serialVersionUID = 6343365699042275217

報(bào)錯(cuò)結(jié)果為序列化與反序列化產(chǎn)生的 serialVersionUID 不一致。

接下來我們?cè)谏厦?User 類的基礎(chǔ)上顯示指定一個(gè) serialVersionUID

private static final long serialVersionUID = 1L;

再執(zhí)行上述步驟, 測(cè)試結(jié)果如下:

序列化前的結(jié)果為:User{name=‘織女’, age=18} 反序列化后的結(jié)果為:User{name=‘織女’, age=18, sex=‘null’}

顯示指定 serialVersionUID 后就解決了序列化與反序列化產(chǎn)生的 serialVersionUID 不一致的問題。

五、Java 序列化的其他特性

先說結(jié)論, 被 transient 關(guān)鍵字修飾的屬性不會(huì)被序列化, static 屬性也不會(huì)被序列化.

我們來測(cè)試下這個(gè)結(jié)論:

(1) User 類

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private Integer age;
    private transient String sex;
    private static String signature = "你眼中的世界就是你自己的樣子";
    @Override
    public String toString() {
        return "User{" +
                " + name + '\\'' +
                ", age=" + age +
                ", sex='" + sex +'\\'' +
                ", signature='" + signature + '\\'' +
                '}';
    }
    // 省略 get/set 方法
}

(2) 測(cè)試類

public class SerializeTest {
    private static File file = new File("D:/Desktop/user.txt");
    private static void serialize(User user) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(user);
        oos.close();
    }
    private static User deserialize() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        return (User) ois.readObject();
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User();
        user.setName("織女");
        user.setAge(18);
        user.setSex("woman");
        System.out.println("序列化前的結(jié)果為:" + user);
        serialize(user);
        User user1 = deserialize();
        System.out.println("反序列化后的結(jié)果為:" + user1);
    }
}

(3) 結(jié)果

先注釋掉反序列化代碼, 執(zhí)行序列化代碼, 然后修改 User 類 signature = “我的眼里只有你”,再注釋掉序列化代碼執(zhí)行反序列化代碼, 最后結(jié)果如下:

序列化前的結(jié)果: User{name=‘織女’, age=18, sex=‘woman’, signature=‘你眼中的世界就是你自己的樣子’}

反序列化后的結(jié)果: User{name=‘織女’, age=18, sex=‘null’, signature=‘我的眼里只有你’}

六、static 屬性為什么不會(huì)被序列化?

因?yàn)樾蛄谢轻槍?duì)對(duì)象而言的,而 static 屬性優(yōu)先于對(duì)象存在, 隨著類的加載而加載, 所以不會(huì)被序列化.

看到這個(gè)結(jié)論, 是不是有人會(huì)問, serialVersionUID 也被 static 修飾, 為什么 serialVersionUID 會(huì)被序列化?

其實(shí) serialVersionUID 屬性并沒有被序列化, JVM 在序列化對(duì)象時(shí)會(huì)自動(dòng)生成一個(gè) serialVersionUID, 然后將我們顯示指定的 serialVersionUID 屬性值賦給自動(dòng)生成的 serialVersionUID。

到此這篇關(guān)于Java中序列化與反序列化的特性解讀的文章就介紹到這了,更多相關(guān)Java序列化與反序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Spring Boot 屬性配置和自定義屬性配置

    淺談Spring Boot 屬性配置和自定義屬性配置

    這篇文章主要介紹了淺談Spring Boot 屬性配置和自定義屬性配置,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • 一文解決pom.xml報(bào)錯(cuò)Dependency "xxx" not found的問題

    一文解決pom.xml報(bào)錯(cuò)Dependency "xxx" not f

    我們?cè)谑褂胢aven進(jìn)行jar包管理時(shí)有時(shí)會(huì)遇到pom.xml中報(bào)錯(cuò)Dependency “XXX” not found,所以在本文中將給大家介紹一下pom.xml報(bào)錯(cuò)Dependency "xxx" not found的解決方案,需要的朋友可以參考下
    2024-01-01
  • Java8新特性O(shè)ptional類及新時(shí)間日期API示例詳解

    Java8新特性O(shè)ptional類及新時(shí)間日期API示例詳解

    這篇文章主要為大家介紹了Java8新特性O(shè)ptional類及新時(shí)間日期API示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Springboot實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel的方法

    Springboot實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel的方法

    今天帶各位小伙伴學(xué)習(xí)Springboot實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel的方法,文中有非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • 詳解Java中AC自動(dòng)機(jī)的原理與實(shí)現(xiàn)

    詳解Java中AC自動(dòng)機(jī)的原理與實(shí)現(xiàn)

    AC自動(dòng)機(jī)是一個(gè)多模式匹配算法,在模式匹配領(lǐng)域被廣泛應(yīng)用。本文將詳細(xì)為大家介紹AC自動(dòng)機(jī)的原理與實(shí)現(xiàn)方法,感興趣的可以了解一下
    2022-05-05
  • Spring 定時(shí)任務(wù)@Scheduled 注解四大參數(shù)用法解析

    Spring 定時(shí)任務(wù)@Scheduled 注解四大參數(shù)用法解析

    本文詳細(xì)介紹了Spring框架中使用@Scheduled注解實(shí)現(xiàn)定時(shí)任務(wù)的方法,重點(diǎn)講解了fixedRate、fixedDelay、cron和initialDelay這四個(gè)參數(shù)的用法,并通過實(shí)例代碼進(jìn)行了詳細(xì)說明,感興趣的朋友一起看看吧
    2025-01-01
  • Java?Stream實(shí)現(xiàn)多字段分組groupingBy操作詳解

    Java?Stream實(shí)現(xiàn)多字段分組groupingBy操作詳解

    Stream是Java8的一個(gè)新特性,主要用戶集合數(shù)據(jù)的處理,如排序、過濾、去重等等功能,本文就來講講如何利用Stream實(shí)現(xiàn)比較優(yōu)雅的按多字段進(jìn)行分組groupingBy吧
    2023-06-06
  • SpringBoot分布式文件存儲(chǔ)數(shù)據(jù)庫mongod

    SpringBoot分布式文件存儲(chǔ)數(shù)據(jù)庫mongod

    MongoDB是一個(gè)基于分布式文件存儲(chǔ)的NoSQL數(shù)據(jù)庫,由C++語言編寫,旨在為Web應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。MongoDB是一個(gè)介于關(guān)系數(shù)據(jù)庫和非關(guān)系數(shù)據(jù)庫之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫中功能最豐富最像關(guān)系數(shù)據(jù)庫的
    2023-02-02
  • 利用java反射機(jī)制實(shí)現(xiàn)自動(dòng)調(diào)用類的簡單方法

    利用java反射機(jī)制實(shí)現(xiàn)自動(dòng)調(diào)用類的簡單方法

    下面小編就為大家?guī)硪黄胘ava反射機(jī)制實(shí)現(xiàn)自動(dòng)調(diào)用類的簡單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-08-08
  • 啟動(dòng)異常invalid constant type:15的解決方案

    啟動(dòng)異常invalid constant type:15的解決方案

    今天小編就為大家分享一篇關(guān)于啟動(dòng)異常invalid constant type:15的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12

最新評(píng)論