日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java序列化和反序列化以及序列化ID的作用分析

發(fā)布時間:2025/3/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java序列化和反序列化以及序列化ID的作用分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?java序列化和反序列化

一、概念

? ? ? ?java對象序列化的意思就是將對象的狀態(tài)轉(zhuǎn)化成字節(jié)流,以后可以通過這些值再生成相同狀態(tài)的對象。對象序列化是對象持久化的一種實(shí)現(xiàn)方法,它是將對象的屬性和方法轉(zhuǎn)化為一種序列化的形式用于存儲和傳輸。反序列化就是根據(jù)這些保存的信息重建對象的過程。

? ? ? ?序列化:將java對象轉(zhuǎn)化為字節(jié)序列的過程。

? ? ? ?反序列化:將字節(jié)序列轉(zhuǎn)化為java對象的過程。


二、為什么要序列化和反序列化

? ??? ?我們知道,當(dāng)兩個進(jìn)程進(jìn)行遠(yuǎn)程通信時,可以相互發(fā)送各種類型的數(shù)據(jù),包括文本、圖片、音頻、視頻等,?而這些數(shù)據(jù)都會以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳送。那么當(dāng)兩個Java進(jìn)程進(jìn)行通信時,能否實(shí)現(xiàn)進(jìn)程間的對象傳送呢?答案是可以的。如何做到呢?這就需要Java序列化與反序列化了。換句話說,一方面,發(fā)送方需要把這個Java對象轉(zhuǎn)換為字節(jié)序列,然后在網(wǎng)絡(luò)上傳送;另一方面,接收方需要從字節(jié)序列中恢復(fù)出Java對象。當(dāng)我們明晰了為什么需要Java序列化和反序列化后,我們很自然地會想Java序列化的好處。其好處一是實(shí)現(xiàn)了數(shù)據(jù)的持久化,通過序列化可以把數(shù)據(jù)永久地保存到硬盤上(通常存放在文件里),二是,利用序列化實(shí)現(xiàn)遠(yuǎn)程通信,即在網(wǎng)絡(luò)上傳送對象的字節(jié)序列。


三、涉及到的javaAPI 

? ? ? ? ??java.io.ObjectOutputStream表示對象輸出流,它的writeObject(Object obj)方法可以對參數(shù)指定的obj對象進(jìn)行序列化,把得到的字節(jié)序列寫到一個目標(biāo)輸出流中。

? ? ? ? ??java.io.ObjectInputStream表示對象輸入流,它的readObject()方法源輸入流中讀取字節(jié)序列,再把它們反序列化成為一個對象,并將其返回。

? ? ? ? ?只有實(shí)現(xiàn)了Serializable或Externalizable接口的類的對象才能被序列化,否則拋出異常。


四、序列化和反序列化的步驟

? ? ? ? ?序列化:

? ? ? ? ? ?步驟一:創(chuàng)建一個對象輸出流,它可以包裝一個其它類型的目標(biāo)輸出流,如文件輸出流:

? ? ? ? ? ? ? ? ? ? ? ? ? ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“目標(biāo)地址路徑”));

? ? ? ? ?步驟二:通過對象輸出流的writeObject()方法寫對象:

? ? ? ? ? ? ? ? ? ? ? ? ? out.writeObject("Hello");

? ? ? ? ? ? ? ? ? ? ? ? ? out.writeObject(new Date());

? ? ? ? ?反序列化: ? ?? ??

? ? ? ? ??步驟一:創(chuàng)建一個對象輸入流,它可以包裝一個其它類型輸入流,如文件輸入流:

? ? ? ? ? ? ? ? ? ? ? ? ? ObjectInputStream in = new ObjectInputStream(new fileInputStream(“目標(biāo)地址路徑”));

? ? ? ? ?步驟二:通過對象輸出流的readObject()方法讀取對象:

? ? ? ? ? ? ? ? ? ? ? ? String obj1 = (String)in.readObject();

? ? ? ? ? ? ? ? ? ? ? ? Date obj2 = ?(Date)in.readObject();

? ? ? ? 說明:為了正確讀取數(shù)據(jù),完成反序列化,必須保證向?qū)ο筝敵隽鲗憣ο蟮捻樞蚺c從對象輸入流中讀對象的順序一致。

五、舉個例子

? ? ?? 我們首先寫個Person實(shí)現(xiàn)Serializable接口:

[java]?view plaincopy print?
  • import?java.io.Serializable;??
  • ??
  • /**?
  • ?*??
  • ?*?測試序列化和反序列化?
  • ?*?@author?crazyandcoder?
  • ?*?@date?[2015-8-5?上午11:14:32]?
  • ?*/??
  • public?class?Person?implements?Serializable??{??
  • ??????
  • ????private?int?age;??
  • ????private?String?name;??
  • ????//序列化ID??
  • ????private?static?final?long?serialVersionUID?=?-5809782578272943999L;??
  • ??????
  • ????public?Person()?{}??
  • ??????
  • ????public?int?getAge()?{??
  • ????????return?age;??
  • ????}??
  • ????public?void?setAge(int?age)?{??
  • ????????this.age?=?age;??
  • ????}??
  • ????public?String?getName()?{??
  • ????????return?name;??
  • ????}??
  • ????public?void?setName(String?name)?{??
  • ????????this.name?=?name;??
  • ????}??
  • ??
  • }??
  • ? ? ? ??

    ? ? ? ? ?其次,我們在main()里面寫個方法,執(zhí)行序列化過程:

    [java]?view plaincopy print?
  • import?java.io.FileNotFoundException;??
  • import?java.io.FileOutputStream;??
  • import?java.io.IOException;??
  • import?java.io.ObjectOutputStream;??
  • /**?
  • ?*??
  • ?*?測試序列化和反序列化?
  • ?*?@author?crazyandcoder?
  • ?*?@date?[2015-8-5?上午11:16:14]?
  • ?*/??
  • public?class?ObjSerializeAndDeserializeTest?{???
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????//將Person對象序列化??
  • ????????SerializePerson();??
  • ??
  • ????}??
  • ??????
  • ????/**?
  • ?????*??
  • ?????*?@author?crazyandcoder?
  • ?????*?@Title:?序列化Person對象,將其存儲到?E:/hello.txt文件中?
  • ?????*?@param???
  • ?????*?@return?void??
  • ?????*?@throws??
  • ?????*?@date?[2015-8-5?上午11:21:27]?
  • ?????*/??
  • ????private?static?void?SerializePerson()?{??
  • ????????Person?person?=new?Person();??
  • ????????person.setAge(30);??
  • ????????person.setName("SerializePerson");??
  • ????????ObjectOutputStream?outputStream?=?null;??
  • ????????try?{??
  • ????????????outputStream=new?ObjectOutputStream(new?FileOutputStream("E:/hello.txt"));??
  • ????????????outputStream.writeObject(person);??
  • ????????????System.out.println("序列化成功。");??
  • ????????}?catch?(FileNotFoundException?e)?{??
  • ????????????e.printStackTrace();??????????????
  • ????????}?catch?(IOException?e)?{??
  • ????????????e.printStackTrace();??????????
  • ????????}?finally?{??
  • ????????????try?{??
  • ????????????????outputStream.close();??
  • ????????????}?catch?(IOException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}?????????
  • ????}??
  • }??
  • ? ? ? ? ? ?代碼很簡單,首先創(chuàng)建一個對象輸出流ObjectOutputStream,它可以包裝一個其它類型的目標(biāo)輸出流,如文件輸出流FileOutputStream,并指定存儲的位置為“E:/hello.txt”,然后通過對象輸出流的writeObject()方法寫對象便執(zhí)行了序列化過程。運(yùn)行看一下效果,正確的話便會在控制臺打印“”,并且在本地E盤下會創(chuàng)建一個Hello.txt文件。



    ? ? ? ??

    ? ? ? ? 我們查看一下hello.txt文件中的內(nèi)容,里面是一串字節(jié)序列,打開該文件的時候不要用自帶的記事本打開,因?yàn)樯婕暗阶址幋a的問題,所以顯示的話是一串亂碼,建議用SublimeText打開。


    ? ? ? ???

    ? ? ? ? 我們再寫個方法來反序列化該字節(jié)成Person對象,并打印出里面的值。

    [java]?view plaincopy print?
  • import?java.io.FileInputStream;??
  • import?java.io.FileNotFoundException;??
  • import?java.io.FileOutputStream;??
  • import?java.io.IOException;??
  • import?java.io.ObjectInputStream;??
  • import?java.io.ObjectOutputStream;??
  • /**?
  • ?*??
  • ?*?測試序列化和反序列化?
  • ?*?@author?crazyandcoder?
  • ?*?@date?[2015-8-5?上午11:16:14]?
  • ?*/??
  • public?class?ObjSerializeAndDeserializeTest?{??
  • ??
  • ???????
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????//反序列化生成Person對象??
  • ????????Person?person=DeserializePerson();??
  • ????????System.out.println("name?:"+person.getName());??
  • ????????System.out.println("age??:"+person.getAge());??
  • ??????????
  • ??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?執(zhí)行反序列化過程生產(chǎn)Person對象?
  • ?????*?@author?crazyandcoder?
  • ?????*?@Title:?DeserializePerson??
  • ?????*?@param?@return??
  • ?????*?@return?Person??
  • ?????*?@throws??
  • ?????*?@date?[2015-8-5?下午1:30:12]?
  • ?????*/??
  • ????private?static?Person?DeserializePerson()?{??
  • ??????????
  • ????????Person?person=null;??
  • ????????ObjectInputStream?inputStream=null;??
  • ????????try?{??
  • ????????????inputStream=new?ObjectInputStream(new?FileInputStream("E:/hello.txt"));??
  • ????????????try?{??
  • ????????????????person=(Person)inputStream.readObject();??
  • ????????????????System.out.println("執(zhí)行反序列化過程成功。");??
  • ????????????}?catch?(ClassNotFoundException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}?catch?(FileNotFoundException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?catch?(IOException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?finally?{??
  • ????????????try?{??
  • ????????????????inputStream.close();??
  • ????????????}?catch?(IOException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????????return?person;??
  • ????}??
  • }??
  • ? ? ? ? ?

    ? ? ? ? 執(zhí)行反序列化的代碼也是很簡單的,首先創(chuàng)建一個輸入流對象ObjectInputStream,然后從指定的目錄下“E:/hello.txt”獲取它的字節(jié)序列,然后通過輸入流對象的readObject()方法將其獲得的對象強(qiáng)制轉(zhuǎn)化為Person對象,這就完成了反序列化工作,正確的反序列化成功的情況下控制臺打印輸出為:



    Java?序列化ID的作用


    ? ? ? ?有關(guān)序列化和反序列化的概念,可以查看前一篇《java序列化和反序列化使用總結(jié)》的講解,這一篇主要說明一下序列化過程中出現(xiàn)的問題即java序列化和反序列化中ID的作用。

    ? ? ? ? 在前一篇的介紹中,我們在代碼里會發(fā)現(xiàn)有這樣一個變量:serialVersionUID,那么這個變量serialVersionUID到底具有什么作用呢?能不能去掉呢?


    [java]?view plaincopy print?
  • public?class?Person?implements?Serializable??{??
  • ??????
  • ????private?int?age;??
  • ????private?String?sex;??
  • ????private?String?name;??
  • ????private?String?hobby;??
  • ????//序列化ID??
  • ????private?static?final?long?serialVersionUID?=?-5809782578272943999L;??
  • ????????............??
  • ??
  • }??
  • ? ? ? ?

    ? ? ? ?序列化ID的作用:??

    ? ? ? ?其實(shí),這個序列化ID起著關(guān)鍵的作用,它決定著是否能夠成功反序列化!簡單來說,java的序列化機(jī)制是通過在運(yùn)行時判斷類的serialVersionUID來驗(yàn)證版本一致性的。在進(jìn)行反序列化時,JVM會把傳來的字節(jié)流中的serialVersionUID與本地實(shí)體類中的serialVersionUID進(jìn)行比較,如果相同則認(rèn)為是一致的,便可以進(jìn)行反序列化,否則就會報序列化版本不一致的異常。等會我們可以通過代碼驗(yàn)證一下。

    ? ? ? ?序列化ID如何產(chǎn)生:

    ? ? ? ?當(dāng)我們一個實(shí)體類中沒有顯示的定義一個名為“serialVersionUID”、類型為long的變量時,Java序列化機(jī)制會根據(jù)編譯時的class自動生成一個serialVersionUID作為序列化版本比較,這種情況下,只有同一次編譯生成的class才會生成相同的serialVersionUID。譬如,當(dāng)我們編寫一個類時,隨著時間的推移,我們因?yàn)樾枨蟾膭?#xff0c;需要在本地類中添加其他的字段,這個時候再反序列化時便會出現(xiàn)serialVersionUID不一致,導(dǎo)致反序列化失敗。那么如何解決呢?便是在本地類中添加一個“serialVersionUID”變量,值保持不變,便可以進(jìn)行序列化和反序列化。


    ? ? ? ?驗(yàn)證“serialVersionUID”不一致導(dǎo)致反序列化失敗

    [java]?view plaincopy print?
  • import?java.io.Serializable;??
  • ??
  • /**?
  • ?*??
  • ?*?測試序列化和反序列化?
  • ?*?@author?crazyandcoder?
  • ?*?@date?[2015-8-5?上午11:14:32]?
  • ?*/??
  • public?class?Person?implements?Serializable??{??
  • ??????
  • ????private?int?age;??
  • //??private?String?sex;??
  • //??private?String?name;??
  • //??private?String?hobby;??
  • ????//序列化ID??
  • //??private?static?final?long?serialVersionUID?=?-5809782578272943999L;??
  • ??????
  • //??public?String?getHobby()?{??
  • //??????return?hobby;??
  • //??}??
  • //??
  • //??public?void?setHobby(String?hobby)?{??
  • //??????this.hobby?=?hobby;??
  • //??}??
  • ??
  • ????public?Person()?{}??
  • ??????
  • ????public?int?getAge()?{??
  • ????????return?age;??
  • ????}??
  • ??????
  • ????public?void?setAge(int?age)?{??
  • ????????this.age?=?age;??
  • ????}??
  • ??????
  • //??public?String?getSex()?{??
  • //??????return?sex;??
  • //??}??
  • //??
  • //??public?void?setSex(String?sex)?{??
  • //??????this.sex?=?sex;??
  • //??}??
  • ??????
  • //??public?String?getName()?{??
  • //??????return?name;??
  • //??}??
  • //??public?void?setName(String?name)?{??
  • //??????this.name?=?name;??
  • //??}??
  • ??
  • }??
  • ? ? ? ? 復(fù)用前篇使用到的代碼,首先,我們生成一個本地Person類,里面添加一個字段age,然后將其序列化存于本地E:/hello.txt中,

    [java]?view plaincopy print?
  • import?java.io.FileNotFoundException;??
  • import?java.io.FileOutputStream;??
  • import?java.io.IOException;??
  • import?java.io.ObjectOutputStream;??
  • ??
  • ??
  • /**?
  • ?*??
  • ?*?測試序列化和反序列化?
  • ?*?@author?crazyandcoder?
  • ?*?@date?[2015-8-5?上午11:16:14]?
  • ?*/??
  • public?class?ObjSerializeAndDeserializeTest?{??
  • ??
  • ???????
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????//將Person對象序列化??
  • ????????SerializePerson();??
  • ????}??
  • ??????
  • ??????
  • ????/**?
  • ?????*??
  • ?????*?@author?crazyandcoder?
  • ?????*?@Title:?序列化Person對象,將其存儲到?E:/hello.txt文件中?
  • ?????*?@param???
  • ?????*?@return?void??
  • ?????*?@throws??
  • ?????*?@date?[2015-8-5?上午11:21:27]?
  • ?????*/??
  • ????private?static?void?SerializePerson()?{??
  • ????????Person?person?=new?Person();??
  • ????????person.setAge(30);??
  • ????????ObjectOutputStream?outputStream?=?null;??
  • ????????try?{??
  • ????????????outputStream=new?ObjectOutputStream(new?FileOutputStream("E:/hello.txt"));??
  • ????????????outputStream.writeObject(person);??
  • ????????????System.out.println("序列化成功。");??
  • ????????}?catch?(FileNotFoundException?e)?{??
  • ????????????e.printStackTrace();??
  • ??????????????????
  • ????????}?catch?(IOException?e)?{??
  • ????????????e.printStackTrace();??
  • ??????????????????
  • ????????}?finally?{??
  • ????????????try?{??
  • ????????????????outputStream.close();??
  • ????????????}?catch?(IOException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ??????????
  • ????}??
  • }??
  • ? ? ? ??

    ? ? ? ? 運(yùn)行一下,會在控制臺中打印“序列化成功。”,然后我們在Person類中再添加一個字段,name,然后直接從E:/hello.txt中反序列化,再運(yùn)行一下,看看會出現(xiàn)什么問題。

    [java]?view plaincopy print?
  • import?java.io.FileInputStream;??
  • import?java.io.FileNotFoundException;??
  • import?java.io.FileOutputStream;??
  • import?java.io.IOException;??
  • import?java.io.ObjectInputStream;??
  • import?java.io.ObjectOutputStream;??
  • ??
  • /**?
  • ?*??
  • ?*?測試序列化和反序列化?
  • ?*??
  • ?*?@author?crazyandcoder?
  • ?*?@date?[2015-8-5?上午11:16:14]?
  • ?*/??
  • public?class?ObjSerializeAndDeserializeTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ??
  • ????????//?反序列化生成Person對象??
  • ????????Person?person?=?DeserializePerson();??
  • ????????System.out.println("name?:"?+?person.getName());??
  • ????????System.out.println("age??:"?+?person.getAge());??
  • ????}??
  • ??
  • ????/**?
  • ?????*?執(zhí)行反序列化過程生產(chǎn)Person對象?
  • ?????*??
  • ?????*?@author?crazyandcoder?
  • ?????*?@Title:?DeserializePerson?
  • ?????*?@param?@return?
  • ?????*?@return?Person?
  • ?????*?@throws?
  • ?????*?@date?[2015-8-5?下午1:30:12]?
  • ?????*/??
  • ????private?static?Person?DeserializePerson()?{??
  • ??
  • ????????Person?person?=?null;??
  • ????????ObjectInputStream?inputStream?=?null;??
  • ????????try?{??
  • ????????????inputStream?=?new?ObjectInputStream(new?FileInputStream("E:/hello.txt"));??
  • ????????????try?{??
  • ????????????????person?=?(Person)?inputStream.readObject();??
  • ????????????????System.out.println("執(zhí)行反序列化過程成功。");??
  • ????????????}?catch?(ClassNotFoundException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}?catch?(FileNotFoundException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?catch?(IOException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?finally?{??
  • ????????????try?{??
  • ????????????????inputStream.close();??
  • ????????????}?catch?(IOException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????????return?person;??
  • ????}??
  • }??

  • ? ? ? ?運(yùn)行一下,不出意外,報了一個異常。



    ? ? ??

    ? ? ? 從上面兩張圖便可以看出兩次的序列化ID是不一樣的,導(dǎo)致反序列化失敗。


    總結(jié):

    ? ? ? ?虛擬機(jī)是否允許反序列化,不僅取決于類路徑和功能代碼是否一致,一個非常重要的一點(diǎn)是兩個類的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。



    總結(jié)

    以上是生活随笔為你收集整理的java序列化和反序列化以及序列化ID的作用分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。