国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Java對象為啥要實現Serializable接口?

開發 后端
最近這段時間一直在忙著編寫Java業務代碼,麻木地搬著Ctrl-C、Ctrl-V的磚,在不知道重復了多少次定義Java實體對象時“implements Serializable”的C/V大法后,腦海中突然冒出一個思維(A):問了自己一句“Java實體對象為什么一定要實現Serializable接口呢?”

[[265102]]

導讀

 

最近這段時間一直在忙著編寫Java業務代碼,麻木地搬著Ctrl-C、Ctrl-V的磚,在不知道重復了多少次定義Java實體對象時“implements Serializable”的C/V大法后,腦海中突然冒出一個思維(A):問了自己一句“Java實體對象為什么一定要實現Serializable接口呢?”,關于這個問題,腦海中的另一個思維(B)立馬給出了回復“居然問這么幼稚和基礎的問題,實現Serilizable接口是為了序列化啊!”,思維(A):“哦,好吧!然而,然后呢?”

此時思維(B)陷入了沉默,突然感覺自己有點淺薄了,好像寫了這么多年Java還真是沒有太關注過Serializable這個接口!為什么一定要實現Serializable接口?它的底層原理是什么?為什么一定要序列化,序列化又是什么?關于這些問題,不知道各位讀者朋友有沒有過類似的問題,如果有那么我們就在這篇文章中一起尋找答案吧!當然,如果你對這些問題都很清楚,也歡迎表達看法!

Serializable接口概述

 

Serializable是java.io包中定義的、用于實現Java類的序列化操作而提供的一個語義級別的接口。Serializable序列化接口沒有任何方法或者字段,只是用于標識可序列化的語義。實現了Serializable接口的類可以被ObjectOutputStream轉換為字節流,同時也可以通過ObjectInputStream再將其解析為對象。例如,我們可以將序列化對象寫入文件后,再次從文件中讀取它并反序列化成對象,也就是說,可以使用表示對象及其數據的類型信息和字節在內存中重新創建對象。

而這一點對于面向對象的編程語言來說是非常重要的,因為無論什么編程語言,其底層涉及IO操作的部分還是由操作系統其幫其完成的,而底層IO操作都是以字節流的方式進行的,所以寫操作都涉及將編程語言數據類型轉換為字節流,而讀操作則又涉及將字節流轉化為編程語言類型的特定數據類型。而Java作為一門面向對象的編程語言,對象作為其主要數據的類型載體,為了完成對象數據的讀寫操作,也就需要一種方式來讓JVM知道在進行IO操作時如何將對象數據轉換為字節流,以及如何將字節流數據轉換為特定的對象,而Serializable接口就承擔了這樣一個角色。

下面我們可以通過例子來實現將序列化的對象存儲到文件,然后再將其從文件中反序列化為對象,代碼示例如下:

先定義一個序列化對象User:

  1. public class User implements Serializable { 
  2.     private static final long serialVersionUID = 1L; 
  3.  
  4.     private String userId; 
  5.     private String userName; 
  6.  
  7.     public User(String userId, String userName) { 
  8.         this.userId = userId; 
  9.         this.userName = userName; 
  10.     } 

然后我們編寫測試類,來對該對象進行讀寫操作,我們先測試將該對象寫入一個文件:

  1. public class SerializableTest { 
  2.  
  3.     /** 
  4.      * 將User對象作為文本寫入磁盤 
  5.      */ 
  6.     public static void writeObj() { 
  7.         User user = new User("1001""Joe"); 
  8.         try { 
  9.             ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/guanliyuan/user.txt")); 
  10.             objectOutputStream.writeObject(user); 
  11.             objectOutputStream.close(); 
  12.         } catch (IOException e) { 
  13.             e.printStackTrace(); 
  14.         } 
  15.     } 
  16.  
  17.     public static void main(String args[]) { 
  18.         writeObj(); 
  19.     } 

運行上述代碼,我們就將User對象及其攜帶的數據寫入了文本user.txt中,我們可以看下user.txt中存儲的數據此時是個什么格式:

 

  1. java.io.NotSerializableException: cn.wudimanong.serializable.User 
  2.     at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) 
  3.     at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) 
  4.     at cn.wudimanong.serializable.SerializableTest.writeObj(SerializableTest.java:19) 
  5.     at cn.wudimanong.serializable.SerializableTest.main(SerializableTest.java:27) 

 

我們看到對象數據以二進制文本的方式被持久化到了磁盤文件中。在進行反序列化測試之前,我們可以嘗試下將User實現Serializable接口的代碼部分去掉,看看此時寫操作是否還能成功,結果如下:

結果不出所料,果然是不可以的,拋出了NotSerializableException異常,提示非可序列化異常,也就是說沒有實現Serializable接口的對象是無法通過IO操作持久化的。

接下來,我們繼續編寫測試代碼,嘗試將之前持久化寫入user.txt文件的對象數據再次轉化為Java對象,代碼如下:

  1. public class SerializableTest { 
  2.     /** 
  3.      * 將類從文本中提取并賦值給內存中的類 
  4.      */ 
  5.     public static void readObj() { 
  6.         try { 
  7.             ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/guanliyuan/user.txt")); 
  8.             try { 
  9.                 Object object = objectInputStream.readObject(); 
  10.                 User user = (User) object; 
  11.                 System.out.println(user); 
  12.             } catch (ClassNotFoundException e) { 
  13.                 e.printStackTrace(); 
  14.             } 
  15.         } catch (IOException e) { 
  16.             e.printStackTrace(); 
  17.         } 
  18.     } 
  19.  
  20.  
  21.     public static void main(String args[]) { 
  22.         readObj(); 
  23.     } 

通過反序列化操作,可以再次將持久化的對象字節流數據通過IO轉化為Java對象,結果如下:

  1. cn.wudimanong.serializable.User@6f496d9f 

此時,如果我們再次嘗試將User實現Serializable接口的代碼部分去掉,發現也無法再文本轉換為序列化對象,報錯信息為:

  1. ava.io.InvalidClassException: cn.wudimanong.serializable.User; class invalid for deserialization 
  2.     at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:157) 
  3.     at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:862) 
  4.     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2038) 
  5.     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568) 
  6.     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428) 
  7.     at cn.wudimanong.serializable.SerializableTest.readObj(SerializableTest.java:31) 
  8.     at cn.wudimanong.serializable.SerializableTest.main(SerializableTest.java:44) 

提示非法類型轉換異常,說明在Java中如何要實現對象的IO讀寫操作,都必須實現Serializable接口,否則代碼就會報錯!

序列化&反序列化

 

通過上面的闡述和示例,相信大家對Serializable接口的作用是有了比較具體的體會了,接下來我們上層到理論層面,看下到底什么是序列化/反序列化。序列化是指把對象轉換為字節序列的過程,我們稱之為對象的序列化,就是把內存中的這些對象變成一連串的字節(bytes)描述的過程。

而反序列化則相反,就是把持久化的字節文件數據恢復為對象的過程。那么什么情況下需要序列化呢?大概有這樣兩類比較常見的場景:1)、需要把內存中的對象狀態數據保存到一個文件或者數據庫中的時候,這個場景是比較常見的,例如我們利用mybatis框架編寫持久層insert對象數據到數據庫中時;2)、網絡通信時需要用套接字在網絡中傳送對象時,如我們使用RPC協議進行網絡通信時;

關于serialVersionUID

 

對于JVM來說,要進行持久化的類必須要有一個標記,只有持有這個標記JVM才允許類創建的對象可以通過其IO系統轉換為字節數據,從而實現持久化,而這個標記就是Serializable接口。而在反序列化的過程中則需要使用serialVersionUID來確定由那個類來加載這個對象,所以我們在實現Serializable接口的時候,一般還會要去盡量顯示地定義serialVersionUID,如:

  1. private static final long serialVersionUID = 1L; 

在反序列化的過程中,如果接收方為對象加載了一個類,如果該對象的serialVersionUID與對應持久化時的類不同,那么反序列化的過程中將會導致InvalidClassException異常。例如,在之前反序列化的例子中,我們故意將User類的serialVersionUID改為2L,如:

  1. private static final long serialVersionUID = 2L; 

那么此時,在反序例化時就會導致異常,如下:

  1. java.io.InvalidClassException: cn.wudimanong.serializable.Userlocal class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 
  2.     at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687) 
  3.     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1880) 
  4.     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746) 
  5.     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037) 
  6.     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568) 
  7.     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428) 
  8.     at cn.wudimanong.serializable.SerializableTest.readObj(SerializableTest.java:31) 
  9.     at cn.wudimanong.serializable.SerializableTest.main(SerializableTest.java:44) 

如果我們在序列化中沒有顯示地聲明serialVersionUID,則序列化運行時將會根據該類的各個方面計算該類默認的serialVersionUID值。但是,Java官方強烈建議所有要序列化的類都顯示地聲明serialVersionUID字段,因為如果高度依賴于JVM默認生成serialVersionUID,可能會導致其與編譯器的實現細節耦合,這樣可能會導致在反序列化的過程中發生意外的InvalidClassException異常。因此,為了保證跨不同Java編譯器實現的serialVersionUID值的一致,實現Serializable接口的必須顯示地聲明serialVersionUID字段。

此外serialVersionUID字段地聲明要盡可能使用private關鍵字修飾,這是因為該字段的聲明只適用于聲明的類,該字段作為成員變量被子類繼承是沒有用處的!有個特殊的地方需要注意的是,數組類是不能顯示地聲明serialVersionUID的,因為它們始終具有默認計算的值,不過數組類反序列化過程中也是放棄了匹配serialVersionUID值的要求。

參考資料:

https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html?is-external=true

http://www.tutorialspoint.com/java/java_serialization.htm

責任編輯:武曉燕 來源: 無敵碼農
相關推薦

2020-03-11 16:20:03

Serializabl接口Java

2023-10-20 08:06:07

configMap容器

2016-12-05 18:32:08

序列化androidjava

2023-12-26 07:26:07

Java序列化反序列化機制

2023-08-02 08:27:13

2023-09-12 07:24:07

Java序列化接口

2024-04-03 11:40:58

SYN服務器序號

2017-11-06 08:41:53

互聯網分層架構前后端

2020-09-29 07:42:34

互聯網分層架構前后端分離

2011-03-18 19:37:38

Eventable接口QtWidget

2011-06-28 11:05:19

Qt QWidget Eventable

2011-04-21 13:29:18

惠普4500

2020-02-07 19:24:47

APP權限移動應用

2018-04-03 13:10:27

Java對象克隆

2012-02-15 10:37:38

JavaJava Socket

2018-12-29 15:41:41

阿里巴巴程序員serialVersi

2019-12-20 11:17:35

SerialVersionUID

2023-03-09 08:23:07

序列化?接口方法

2009-01-04 09:08:30

面向對象繼承接口

2022-08-27 11:02:04

InnoDB數據庫索引
點贊
收藏

51CTO技術棧公眾號

中文字幕在线影院| av大全在线免费看| 国产精品你懂的| 色多多视频在线播放| 久久久精品蜜桃| 成人精品一区二区三区免费| 欧美日韩激情一区| 国产成+人+综合+亚洲欧美| 亚洲人在线视频| 视频在线日韩| 国产精品视频999| 久久 天天综合| 亚洲网站情趣视频| 亚洲国产黄色片| 中文字幕精品影院| 大胆欧美熟妇xx| 欧美性受极品xxxx喷水| 一区二区免费| 国产精品久久久久久久乖乖| 在线播放日韩导航| 成人性爱视频在线观看| 日本一区二区高清不卡| 欧美老女人性开放| 欧美日韩精品一二三区| 呦呦在线视频| 中文字幕在线亚洲| 在线视频超级| 国产91免费看片| 另类图片国产| www日韩在线观看| 日本电影亚洲天堂一区| 成人av资源网址| 欧洲精品在线播放| 欧美日本一道本在线视频| 日本午夜精品| 欧美交换配乱吟粗大25p| 国产精品激情偷乱一区二区∴| 色视频在线播放| 亚洲国产日韩精品在线| 波多野结衣一区| av观看免费在线| 国色天香一区二区| 国产特级淫片免费看| 亚洲精品国产精品国自产观看浪潮| 蜜桃a∨噜噜一区二区三区| 热久久最新网址| 欧美精品精品一区| 亚洲涩涩av| 浓精h攵女乱爱av| 亚洲视频一区二区| 三级欧美韩日大片在线看| 在线视频1区| 国产91精品久久久| 日本一区二区成人在线| 精品免费av在线 | 亚洲成人福利在线观看| 亚洲第一页自拍| 日本视频免费一区| 91精品专区| av观看久久| 色菇凉天天综合网| 一区二区国产在线| 可以直接在线观看的av| 成人国产精品一区二区| 欧美限制电影| 欧美日夜夜逼| 亚洲自拍在线观看| 欧美日韩三级一区二区| 蜜乳av一区二区| 亚洲伦理久久| 久久久久久久9| 久久91亚洲精品中文字幕奶水| 97se亚洲国产综合自在线观| 亚洲高清999| av最新网址| 亚洲欧洲专区| 蜜臀av性久久久久蜜臀av| 日韩欧美一区二区久久婷婷| 一区二区亚洲视频| 日本欧美在线观看| 黄色小说在线播放| 99亚洲乱人伦aⅴ精品| av日韩精品| 在线中文av| 一本二本三本亚洲码| 久久久av亚洲男天堂| 色综合欧美在线| 91视视频在线直接观看在线看网页在线看 | 成人免费无遮挡| 天天夜夜亚洲| 无人在线观看的免费高清视频 | 性一交一乱一区二区洋洋av| 国产一区二区高清在线| 日本美女高清在线观看免费| www.99色| 久久免费一级片| 成人羞羞视频免费| 国产精品美女在线| 久久99精品国产99久久6尤物| 欧美一卡2卡3卡4卡| 一区二区在线观看免费| 91小视频在线| 成人性视频网站| 美女www一区二区| 亚洲一区视频| 午夜激情久久| 国产精品久久久久无码av| 美女av一区| 麻豆一区一区三区四区| 123成人网| 国产精品扒开腿做爽爽爽视频软件| 黄网站在线播放| 成人午夜在线影视| 国产在线看片| 亚洲日本视频| 五月国产精品| 你懂的在线观看一区二区| 伊人久久大香线蕉综合影院首页| 黑人精品视频| 99re66热这里只有精品4| 我要色综合中文字幕| 中文字幕亚洲欧美日韩在线不卡| 精品国免费一区二区三区| 在线观看日产精品| 欧美性猛交xxxxxxxx| 欧美午夜电影网| 日韩精品一区二区三区第95| 国产一区二区三区在线播放免费观看| 日韩视频一区二区在线观看| 亚洲国产精品视频在线观看 | 性欧美freesex顶级少妇| 992tv国产精品成人影院| 99re6热只有精品免费观看| 亚洲精品白浆高清| 综合天天久久| 久久福利一区| 成人av资源在线| 日韩理论在线观看| 欧美性猛交xxxx乱大交蜜桃| 精品国产乱码久久久久久浪潮 | 999精品视频在线| 亚洲福利二区| 中国日本在线视频中文字幕| 三妻四妾的电影电视剧在线观看| 在线视频成人| 欧美一区三区| 日韩av不卡一区二区| 欧美国产精品一区二区三区| 精品国产99国产精品| 国产精品视频自在线| 欧美一级爱爱视频| 岛国大片在线观看| 一区二区免费| 青青草国产精品97视觉盛宴| 亚洲一区在线播放| 伊人久久五月天| 国内精品久久国产| 日韩精品一区二区三区久久| 成人a在线视频免费观看| 亚洲资源网你懂的| 国产精品久久久久久久岛一牛影视| 精品欧美黑人一区二区三区| 91日韩在线播放| 午夜av电影| 大陆精大陆国产国语精品| 成人高清电影网站| 无需播放器亚洲| 综合欧美一区二区三区| 深夜福利国产精品| 加勒比海盗1在线观看免费国语版| 9色在线视频网站| 天天操夜夜操国产精品| 亚洲免费观看高清在线观看| 久久香蕉频线观| 日本a在线天堂| 这里有精品可以观看| 免费成人av在线| 欧美一级片在线看| 日韩高清av电影| 国产精品一二三产区| 日韩精品乱码免费| 日韩av在线网站| 人妻激情另类乱人伦人妻| 性欧美freesex顶级少妇| 怡红院精品视频在线观看极品| 在线亚洲免费视频| 风间由美一区二区av101 | 日韩在线观看免费全集电视剧网站 | 青青草成人在线| 日本电影一区二区| 久久久91精品国产一区二区精品 | 欧美激情亚洲精品| 国产精品日韩欧美大师| 日本日本19xxxⅹhd乱影响| a成人v在线| 91麻豆精东视频| 日本免费在线精品| yw视频在线观看| 国产精品综合视频| 欧美激情综合色综合啪啪五月|