<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java序列化和反序列化為什么要實(shí)現(xiàn)Serializable接口

          共 7604字,需瀏覽 16分鐘

           ·

          2021-02-09 07:14

          由于公眾號(hào)文章推送規(guī)則的改變,大家能準(zhǔn)時(shí)收到我們的文章推送,請(qǐng)將公眾號(hào):?JAVA?設(shè)為星標(biāo)~這樣就不會(huì)錯(cuò)過(guò)每一篇精彩的推送啦~

          來(lái)源:tyshawnlee.blog.csdn.net/article/details/100097019


          目錄

          • 序列化和反序列化
          • 什么時(shí)候需要用到序列化和反序列化呢?
          • 實(shí)現(xiàn)序列化和反序列化為什么要實(shí)現(xiàn) Serializable 接口?
          • 實(shí)現(xiàn) Serializable 接口就算了,為什么還要顯示指定 serialVersionUID 的值?
          • Java 序列化的其他特性
          • static 屬性為什么不會(huì)被序列化?

          最近公司的在做服務(wù)化, 需要把所有 model 包里的類都實(shí)現(xiàn) Serializable 接口,同時(shí)還要顯示指定 serialVersionUID 的值。聽(tīng)到這個(gè)需求,我腦海里就突然出現(xiàn)了好幾個(gè)問(wèn)題,比如說(shuō):

          • 序列化和反序列化是什么?
          • 實(shí)現(xiàn)序列化和反序列化為什么要實(shí)現(xiàn) Serializable 接口?
          • 實(shí)現(xiàn) Serializable 接口就算了, 為什么還要顯示指定 serialVersionUID 的值?
          • 我要為 serialVersionUID 指定個(gè)什么值?

          下面我們來(lái)一一解答這幾個(gè)問(wèn)題.

          序列化和反序列化

          • 序列化:把對(duì)象轉(zhuǎn)換為字節(jié)序列的過(guò)程稱為對(duì)象的序列化.
          • 反序列化:把字節(jié)序列恢復(fù)為對(duì)象的過(guò)程稱為對(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è)很大的疑問(wèn)? 我們?cè)谂c瀏覽器交互時(shí),還有將內(nèi)存中的對(duì)象持久化到數(shù)據(jù)庫(kù)中時(shí),好像都沒(méi)有去進(jìn)行序列化和反序列化, 因?yàn)槲覀兌紱](méi)有實(shí)現(xiàn) Serializable 接口, 但一直正常運(yùn)行。

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

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

          理由:

          服務(wù)器與瀏覽器交互時(shí)真的沒(méi)有用到 Serializable 接口嗎?JSON 格式實(shí)際上就是將一個(gè)對(duì)象轉(zhuǎn)化為字符串, 所以服務(wù)器與瀏覽器交互時(shí)的數(shù)據(jù)格式其實(shí)是字符串,我們來(lái)看來(lái) 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è)賮?lái)看對(duì)象持久化到數(shù)據(jù)庫(kù)中時(shí)的情況, Mybatis 數(shù)據(jù)庫(kù)映射文件里的 insert 代碼:

          <insert?id="insertUser"?parameterType="org.tyshawn.bean.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 接口, 那自己去寫一套序列化和反序列化代碼也行,至于具體怎么寫, Google 一下你就知道了.

          為什么還要指定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í)際開(kāi)發(fā)中, 不顯示指定 serialVersionUID 的情況會(huì)導(dǎo)致什么問(wèn)題?如果我們的類寫完后不再修改,那當(dāng)然不會(huì)有問(wèn)題。

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

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

          (1) User 類

          不顯示指定 serialVersionUID.

          public?class?User?implements?Serializable?{

          ????private?String?name;
          ????private?Integer?age;

          ????public?String?getName()?{
          ????????return?name;
          ????}

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

          ????public?Integer?getAge()?{
          ????????return?age;
          ????}

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

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

          (2) 測(cè)試類

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

          public?class?SerializableTest?{

          ????private?static?void?serialize(User?user)?throws?Exception?{
          ????????ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream(new?File("D:\\\\111.txt")));
          ????????oos.writeObject(user);
          ????????oos.close();
          ????}

          ????private?static?User?deserialize()?throws?Exception{
          ????????ObjectInputStream?ois?=?new?ObjectInputStream(new?FileInputStream(new?File("D:\\\\111.txt")));
          ????????return?(User)?ois.readObject();
          ????}


          ????public?static?void?main(String\[\]?args)?throws?Exception?{
          ????????User?user?=?new?User();
          ????????user.setName("tyshawn");
          ????????user.setAge(18);
          ????????System.out.println("序列化前的結(jié)果:?"?+?user);

          ????????serialize(user);

          ????????User?dUser?=?deserialize();
          ????????System.out.println("反序列化后的結(jié)果:?"+?dUser);
          ????}
          }

          (3) 結(jié)果

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

          public?class?User?implements?Serializable?{

          ????private?String?name;
          ????private?Integer?age;
          ????private?String?sex;

          ????public?String?getName()?{
          ????????return?name;
          ????}

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

          ????public?Integer?getAge()?{
          ????????return?age;
          ????}

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

          ????public?String?getSex()?{
          ????????return?sex;
          ????}

          ????public?void?setSex(String?sex)?{
          ????????this.sex?=?sex;
          ????}

          ????@Override
          ????public?String?toString()?{
          ????????return?"User{"?+
          ????????????????"?+?name?+?'\\''?+
          ????????????????"
          ,?age="?+?age?+
          ????????????????"
          ,?sex='"?+?sex?+?'\\''?+
          ????????????????'}';
          ????}
          }


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

          序列化前的結(jié)果: User{name='tyshawn', age=18} Exception in thread "main" java.io.InvalidClassException: org.tyshawn.SerializeAndDeserialize.User; local class incompatible: stream classdesc serialVersionUID = 1035612825366363028, local class serialVersionUID = -1830850955895931978

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

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

          private?static?final?long?serialVersionUID?=?1L;

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

          序列化前的結(jié)果: User{name='tyshawn', age=18} 反序列化后的結(jié)果: User{name='tyshawn', age=18, sex='null'}

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

          Java 序列化的其他特性

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

          我們來(lái)測(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?=?"你眼中的世界就是你自己的樣子";

          ????public?String?getName()?{
          ????????return?name;
          ????}

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

          ????public?Integer?getAge()?{
          ????????return?age;
          ????}

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

          ????public?String?getSex()?{
          ????????return?sex;
          ????}

          ????public?void?setSex(String?sex)?{
          ????????this.sex?=?sex;
          ????}

          ????public?static?String?getSignature()?{
          ????????return?signature;
          ????}

          ????public?static?void?setSignature(String?signature)?{
          ????????User.signature?=?signature;
          ????}

          ????@Override
          ????public?String?toString()?{
          ????????return?"User{"?+
          ????????????????"?+?name?+?'\\''?+
          ????????????????"
          ,?age="?+?age?+
          ????????????????"
          ,?sex='"?+?sex?+'\\''?+
          ????????????????",?signature='"?+?signature?+?'\\''?+
          ????????????????'
          }';
          ????}
          }

          (2) 測(cè)試類

          public?class?SerializableTest?{

          ????private?static?void?serialize(User?user)?throws?Exception?{
          ????????ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream(new?File("D:\\\\111.txt")));
          ????????oos.writeObject(user);
          ????????oos.close();
          ????}

          ????private?static?User?deserialize()?throws?Exception{
          ????????ObjectInputStream?ois?=?new?ObjectInputStream(new?FileInputStream(new?File("D:\\\\111.txt")));
          ????????return?(User)?ois.readObject();
          ????}


          ????public?static?void?main(String\[\]?args)?throws?Exception?{
          ????????User?user?=?new?User();
          ????????user.setName("tyshawn");
          ????????user.setAge(18);
          ????????user.setSex("man");
          ????????System.out.println("序列化前的結(jié)果:?"?+?user);

          ????????serialize(user);

          ????????User?dUser?=?deserialize();
          ????????System.out.println("反序列化后的結(jié)果:?"+?dUser);
          ????}
          }

          (3) 結(jié)果

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

          序列化前的結(jié)果: User{name='tyshawn', age=18, sex='man', signature='你眼中的世界就是你自己的樣子'} 反序列化后的結(jié)果: User{name='tyshawn', age=18, sex='null', signature='我的眼里只有你'}

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

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

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

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




          最近有讀者想要分布式的項(xiàng)目,還有想要商城的,還有想要springboot,springcloud,k8s等等,這次直接分享幾乎涵蓋了我們java程序員的大部分技術(shù)桟,可以說(shuō)真的非常全面了。強(qiáng)烈建議大家都上手做一做,而且以后肯定用的上。資料包含高清視頻+課件+源碼……

          掃以下二維碼并回復(fù)“99”即可獲取


          掃描上方二維碼,關(guān)注并回復(fù)【99】馬上獲取


          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色做爱视频 | 蜜桃成人AV| 成年人电影久久 | 蜜桃精品视频在线观看 | www.av动漫 |