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

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

 更新時(shí)間:2023年08月10日 09:21:27   作者:ycfxhsw  
這篇文章主要介紹了Java中序列化與反序列化的特性解讀,當(dāng)我們需要將內(nèi)存中的對(duì)象持久化到磁盤,數(shù)據(jù)庫(kù)中時(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ù)庫(kù)中時(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ù)庫(kù)中時(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ù)庫(kù)中時(shí)的情況, Mybatis 數(shù)據(jù)庫(kù)映射文件里的 insert 代碼:

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

實(shí)際上我們并不是將整個(gè)對(duì)象持久化到數(shù)據(jù)庫(kù)中, 而是將對(duì)象中的屬性持久化到數(shù)據(jù)庫(kù)中, 而這些屬性都是實(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)文章

最新評(píng)論

南靖县| 师宗县| 南澳县| 高清| 南丰县| 乐昌市| 八宿县| 榆树市| 靖西县| 个旧市| 夏津县| 融水| 乌鲁木齐县| 伽师县| 墨竹工卡县| 普定县| 邹城市| 北碚区| 石嘴山市| 南投市| 邳州市| 海阳市| 竹山县| 丰都县| 潜江市| 呼伦贝尔市| 什邡市| 靖远县| 阳江市| 长沙市| 南江县| 仪陇县| 灵寿县| 邵东县| 潼关县| 偏关县| 浦城县| 金门县| 西吉县| 岳阳县| 紫云|