java序列化和反序列化以及序列化ID的作用分析
?java序列化和反序列化
一、概念
? ? ? ?java對象序列化的意思就是將對象的狀態轉化成字節流,以后可以通過這些值再生成相同狀態的對象。對象序列化是對象持久化的一種實現方法,它是將對象的屬性和方法轉化為一種序列化的形式用于存儲和傳輸。反序列化就是根據這些保存的信息重建對象的過程。
? ? ? ?序列化:將java對象轉化為字節序列的過程。
? ? ? ?反序列化:將字節序列轉化為java對象的過程。
二、為什么要序列化和反序列化
? ??? ?我們知道,當兩個進程進行遠程通信時,可以相互發送各種類型的數據,包括文本、圖片、音頻、視頻等,?而這些數據都會以二進制序列的形式在網絡上傳送。那么當兩個Java進程進行通信時,能否實現進程間的對象傳送呢?答案是可以的。如何做到呢?這就需要Java序列化與反序列化了。換句話說,一方面,發送方需要把這個Java對象轉換為字節序列,然后在網絡上傳送;另一方面,接收方需要從字節序列中恢復出Java對象。當我們明晰了為什么需要Java序列化和反序列化后,我們很自然地會想Java序列化的好處。其好處一是實現了數據的持久化,通過序列化可以把數據永久地保存到硬盤上(通常存放在文件里),二是,利用序列化實現遠程通信,即在網絡上傳送對象的字節序列。
三、涉及到的javaAPI
? ? ? ? ??java.io.ObjectOutputStream表示對象輸出流,它的writeObject(Object obj)方法可以對參數指定的obj對象進行序列化,把得到的字節序列寫到一個目標輸出流中。
? ? ? ? ??java.io.ObjectInputStream表示對象輸入流,它的readObject()方法源輸入流中讀取字節序列,再把它們反序列化成為一個對象,并將其返回。
? ? ? ? ?只有實現了Serializable或Externalizable接口的類的對象才能被序列化,否則拋出異常。
四、序列化和反序列化的步驟
? ? ? ? ?序列化:
? ? ? ? ? ?步驟一:創建一個對象輸出流,它可以包裝一個其它類型的目標輸出流,如文件輸出流:
? ? ? ? ? ? ? ? ? ? ? ? ? ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“目標地址路徑”));
? ? ? ? ?步驟二:通過對象輸出流的writeObject()方法寫對象:
? ? ? ? ? ? ? ? ? ? ? ? ? out.writeObject("Hello");
? ? ? ? ? ? ? ? ? ? ? ? ? out.writeObject(new Date());
? ? ? ? ?反序列化: ? ?? ??
? ? ? ? ??步驟一:創建一個對象輸入流,它可以包裝一個其它類型輸入流,如文件輸入流:
? ? ? ? ? ? ? ? ? ? ? ? ? ObjectInputStream in = new ObjectInputStream(new fileInputStream(“目標地址路徑”));
? ? ? ? ?步驟二:通過對象輸出流的readObject()方法讀取對象:
? ? ? ? ? ? ? ? ? ? ? ? String obj1 = (String)in.readObject();
? ? ? ? ? ? ? ? ? ? ? ? Date obj2 = ?(Date)in.readObject();
? ? ? ? 說明:為了正確讀取數據,完成反序列化,必須保證向對象輸出流寫對象的順序與從對象輸入流中讀對象的順序一致。
五、舉個例子
? ? ?? 我們首先寫個Person實現Serializable接口:
[java]?view plaincopy print?
? ? ? ??
? ? ? ? ?其次,我們在main()里面寫個方法,執行序列化過程:
[java]?view plaincopy print?
? ? ? ??
? ? ? ? 我們查看一下hello.txt文件中的內容,里面是一串字節序列,打開該文件的時候不要用自帶的記事本打開,因為涉及到字符編碼的問題,所以顯示的話是一串亂碼,建議用SublimeText打開。
? ? ? ???
? ? ? ? 我們再寫個方法來反序列化該字節成Person對象,并打印出里面的值。
[java]?view plaincopy print?
? ? ? ? ?
? ? ? ? 執行反序列化的代碼也是很簡單的,首先創建一個輸入流對象ObjectInputStream,然后從指定的目錄下“E:/hello.txt”獲取它的字節序列,然后通過輸入流對象的readObject()方法將其獲得的對象強制轉化為Person對象,這就完成了反序列化工作,正確的反序列化成功的情況下控制臺打印輸出為:
Java?序列化ID的作用
? ? ? ?有關序列化和反序列化的概念,可以查看前一篇《java序列化和反序列化使用總結》的講解,這一篇主要說明一下序列化過程中出現的問題即java序列化和反序列化中ID的作用。
? ? ? ? 在前一篇的介紹中,我們在代碼里會發現有這樣一個變量:serialVersionUID,那么這個變量serialVersionUID到底具有什么作用呢?能不能去掉呢?
[java]?view plaincopy print?
? ? ? ?序列化ID的作用:??
? ? ? ?其實,這個序列化ID起著關鍵的作用,它決定著是否能夠成功反序列化!簡單來說,java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地實體類中的serialVersionUID進行比較,如果相同則認為是一致的,便可以進行反序列化,否則就會報序列化版本不一致的異常。等會我們可以通過代碼驗證一下。
? ? ? ?序列化ID如何產生:
? ? ? ?當我們一個實體類中沒有顯示的定義一個名為“serialVersionUID”、類型為long的變量時,Java序列化機制會根據編譯時的class自動生成一個serialVersionUID作為序列化版本比較,這種情況下,只有同一次編譯生成的class才會生成相同的serialVersionUID。譬如,當我們編寫一個類時,隨著時間的推移,我們因為需求改動,需要在本地類中添加其他的字段,這個時候再反序列化時便會出現serialVersionUID不一致,導致反序列化失敗。那么如何解決呢?便是在本地類中添加一個“serialVersionUID”變量,值保持不變,便可以進行序列化和反序列化。
? ? ? ?驗證“serialVersionUID”不一致導致反序列化失敗
[java]?view plaincopy print?
[java]?view plaincopy print?
? ? ? ? 運行一下,會在控制臺中打印“序列化成功。”,然后我們在Person類中再添加一個字段,name,然后直接從E:/hello.txt中反序列化,再運行一下,看看會出現什么問題。
[java]?view plaincopy print?
? ? ? ?運行一下,不出意外,報了一個異常。
? ? ??
? ? ? 從上面兩張圖便可以看出兩次的序列化ID是不一樣的,導致反序列化失敗。
總結:
? ? ? ?虛擬機是否允許反序列化,不僅取決于類路徑和功能代碼是否一致,一個非常重要的一點是兩個類的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。
總結
以上是生活随笔為你收集整理的java序列化和反序列化以及序列化ID的作用分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java开发微信公众平台(一)-- 服务
- 下一篇: hibernate三种状态:临时状态、游