Java中的序列化、反序列化-serializable和serialversionUID


在Java項目中,我們經常對實體類進行implement serializable,在實體類中又加上一句

private static final long serialVersionUID = 5177165015785112433L;

最開始只知道是跟實體類的序列化有關,但是沒有深究,昨天突然想起來了,於是想知道到底是什么東西,在這里小手一抖,記錄一下......


這里補充一下小知識:

  1、序列化、反序列化:

  序列化:將對象轉化為字節序列的過程;

  反序列化:將字節序列反轉成對象的過程。  具體看到下面的例子就明白了

  2、在io流中,有ObjectInputStream、ObjectoutputStream,這倆個在用在實體對象時,要求對象必須實現serializable,表示該對象可被序列化。

 一、首先我們嘗試一下,實體類不進行implement Serializable,分別對實體類進行序列化和反序列化

  咱的實體類:

 1 package com.example.io.serializable;
 2 
 3 import lombok.Data;
 4 
 5 import java.io.Serializable;
 6 
 7 /**
 8  * @program: io
 9  * @description:
10  * @author: liuqj
11  * @create: 2020-06-17 09:41
12  **/
13 @Data
14 public class Book {
15 
16     private int id;
17     private String name;
18     private Double price;
19 }

 

 測試: 

 1     package com.example.io.serializable;
 2 
 3     import java.io.*;
 4 
 5     /**
 6      * @program: io
 7      * @description:
 8      * @author: liuqj
 9      * @create: 2020-06-17 09:43
10      **/
11     public class TestSerializable {
12         public static void main(String[] args) throws IOException, ClassNotFoundException {
13             serializable();
14             deserializable();
15     }
16     static void serializable () throws IOException {
17         Book book = new Book();
18         book.setId(1);
19         book.setName("從大爆炸到黑洞");
20         book.setPrice(100.00);
21         ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("D:\\Personal\\JavaProject\\io\\serializable.txt")));
22         outputStream.writeObject(book);
       outputStream.clouse();
23 System.out.println("序列化成功"); 24 } 25 static void deserializable() throws IOException, ClassNotFoundException { 26 ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("D:\\Personal\\JavaProject\\io\\serializable.txt"))); 27 Book book = (Book) inputStream.readObject();
       inputStream.clouse();
28 System.out.println(book); 29 }

 

運行結果:

 

 

 

 可以看到如果不對實體類進行implement Serializable,那么進行序列化的時候就會報錯。

 

二、對實體進行implement Serializable,但不加serialversionUID。

1 @Data
2 public class Book implements Serializable{
3 
4     private int id;
5     private String name;
6     private Double price;
7 }

 

1、直接進行序列化、反序列化

  運行結果:

   1 序列化成功 2 Book(id=1, name=從大爆炸到黑洞, price=100.0) 3 4 Process finished with exit code 0 

2、先進行序列化,然后修改(刪除)對象中的屬性,再進行反序列化

 1 D:\Work\Jdk\bin\java.exe "-javaagent:D:\Work\Idea\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=54850:D:\Work\Idea\IntelliJ IDEA 2019.3.4\bin" -Dfile.encoding=UTF-8 -classpath D:\Work\Jdk\jre\lib\charsets.jar;D:\Work\Jdk\jre\lib\deploy.jar;D:\Work\Jdk\jre\lib\ext\access-bridge-64.jar;D:\Work\Jdk\jre\lib\ext\cldrdata.jar;D:\Work\Jdk\jre\lib\ext\dnsns.jar;D:\Work\Jdk\jre\lib\ext\jaccess.jar;D:\Work\Jdk\jre\lib\ext\jfxrt.jar;D:\Work\Jdk\jre\lib\ext\localedata.jar;D:\Work\Jdk\jre\lib\ext\nashorn.jar;D:\Work\Jdk\jre\lib\ext\sunec.jar;D:\Work\Jdk\jre\lib\ext\sunjce_provider.jar;D:\Work\Jdk\jre\lib\ext\sunmscapi.jar;D:\Work\Jdk\jre\lib\ext\sunpkcs11.jar;D:\Work\Jdk\jre\lib\ext\zipfs.jar;D:\Work\Jdk\jre\lib\javaws.jar;D:\Work\Jdk\jre\lib\jce.jar;D:\Work\Jdk\jre\lib\jfr.jar;D:\Work\Jdk\jre\lib\jfxswt.jar;D:\Work\Jdk\jre\lib\jsse.jar;D:\Work\Jdk\jre\lib\management-agent.jar;D:\Work\Jdk\jre\lib\plugin.jar;D:\Work\Jdk\jre\lib\resources.jar;D:\Work\Jdk\jre\lib\rt.jar;D:\Personal\JavaProject\io\target\classes;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.1.RELEASE\spring-boot-starter-data-jdbc-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.1.RELEASE\spring-boot-starter-jdbc-2.3.1.RELEASE.jar;D:\Work\Maven\repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\Work\Maven\repository\org\springframework\spring-jdbc\5.2.7.RELEASE\spring-jdbc-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-jdbc\2.0.1.RELEASE\spring-data-jdbc-2.0.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-relational\2.0.1.RELEASE\spring-data-relational-2.0.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-commons\2.3.1.RELEASE\spring-data-commons-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-tx\5.2.7.RELEASE\spring-tx-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-context\5.2.7.RELEASE\spring-context-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-aop\5.2.7.RELEASE\spring-aop-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-expression\5.2.7.RELEASE\spring-expression-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-beans\5.2.7.RELEASE\spring-beans-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter\2.3.1.RELEASE\spring-boot-starter-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot\2.3.1.RELEASE\spring-boot-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.1.RELEASE\spring-boot-autoconfigure-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-logging\2.3.1.RELEASE\spring-boot-starter-logging-2.3.1.RELEASE.jar;D:\Work\Maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Work\Maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Work\Maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\Work\Maven\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\Work\Maven\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\Work\Maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\Work\Maven\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\Work\Maven\repository\org\springframework\spring-core\5.2.7.RELEASE\spring-core-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-jcl\5.2.7.RELEASE\spring-jcl-5.2.7.RELEASE.jar com.example.io.serializable.TestSerializable
 2 Exception in thread "main" java.io.InvalidClassException: com.example.io.serializable.Book; 
    local class incompatible: stream classdesc serialVersionUID = -1858406188231479520, local class serialVersionUID = 4049423394988101590 3 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616) 4 at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843) 5 at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713) 6 at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000) 7 at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535) 8 at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422) 9 at com.example.io.serializable.TestSerializable.deserializable(TestSerializable.java:27) 10 at com.example.io.serializable.TestSerializable.main(TestSerializable.java:14) 11 12 Process finished with exit code 1

 

可以看到反序列化失敗,報錯中顯示,流中的UID和本地的UID不一致導致的反序列化失敗,但我們本地並沒有加serialversionUID啊?

是醬紫滴,雖然我們沒加,但是實現了implement Serializable,該接口會幫我們在本地生成一個UID,但這種默認生成的方式,在進行反序列化時不頂用了,

會出現InvalidClassException異常,原因我也木知。(猜測大概是:序列化時(本地->流),會生成一次UID給到序列化后的內容中,反序列化時(流->本地)又再次生成了一次UID給本地,

此時,流中的UID和新生成的本地UID不同,所以導致無法反序列化)

 

三、實體類implement Serializable 且加上serialversionUID

1 public class Book implements Serializable{
2 
3     private static final Long serialVersionUID = -1858406188231479520L;  //注意final不能少,不然本地的UID在反序列化的過程中會被更改,這句代碼就相當於沒加
4     private int id;
5     private String name;
6     private Double price;
7 }

 

1、先直接進行序列化、反序列化

  結果顯示:nice

1 D:\Work\Jdk\bin\java.exe "-javaagent:D:\Work\Idea\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=55570:D:\Work\Idea\IntelliJ IDEA 2019.3.4\bin" -Dfile.encoding=UTF-8 -classpath D:\Work\Jdk\jre\lib\charsets.jar;D:\Work\Jdk\jre\lib\deploy.jar;D:\Work\Jdk\jre\lib\ext\access-bridge-64.jar;D:\Work\Jdk\jre\lib\ext\cldrdata.jar;D:\Work\Jdk\jre\lib\ext\dnsns.jar;D:\Work\Jdk\jre\lib\ext\jaccess.jar;D:\Work\Jdk\jre\lib\ext\jfxrt.jar;D:\Work\Jdk\jre\lib\ext\localedata.jar;D:\Work\Jdk\jre\lib\ext\nashorn.jar;D:\Work\Jdk\jre\lib\ext\sunec.jar;D:\Work\Jdk\jre\lib\ext\sunjce_provider.jar;D:\Work\Jdk\jre\lib\ext\sunmscapi.jar;D:\Work\Jdk\jre\lib\ext\sunpkcs11.jar;D:\Work\Jdk\jre\lib\ext\zipfs.jar;D:\Work\Jdk\jre\lib\javaws.jar;D:\Work\Jdk\jre\lib\jce.jar;D:\Work\Jdk\jre\lib\jfr.jar;D:\Work\Jdk\jre\lib\jfxswt.jar;D:\Work\Jdk\jre\lib\jsse.jar;D:\Work\Jdk\jre\lib\management-agent.jar;D:\Work\Jdk\jre\lib\plugin.jar;D:\Work\Jdk\jre\lib\resources.jar;D:\Work\Jdk\jre\lib\rt.jar;D:\Personal\JavaProject\io\target\classes;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.1.RELEASE\spring-boot-starter-data-jdbc-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.1.RELEASE\spring-boot-starter-jdbc-2.3.1.RELEASE.jar;D:\Work\Maven\repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\Work\Maven\repository\org\springframework\spring-jdbc\5.2.7.RELEASE\spring-jdbc-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-jdbc\2.0.1.RELEASE\spring-data-jdbc-2.0.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-relational\2.0.1.RELEASE\spring-data-relational-2.0.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-commons\2.3.1.RELEASE\spring-data-commons-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-tx\5.2.7.RELEASE\spring-tx-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-context\5.2.7.RELEASE\spring-context-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-aop\5.2.7.RELEASE\spring-aop-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-expression\5.2.7.RELEASE\spring-expression-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-beans\5.2.7.RELEASE\spring-beans-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter\2.3.1.RELEASE\spring-boot-starter-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot\2.3.1.RELEASE\spring-boot-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.1.RELEASE\spring-boot-autoconfigure-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-logging\2.3.1.RELEASE\spring-boot-starter-logging-2.3.1.RELEASE.jar;D:\Work\Maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Work\Maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Work\Maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\Work\Maven\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\Work\Maven\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\Work\Maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\Work\Maven\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\Work\Maven\repository\org\springframework\spring-core\5.2.7.RELEASE\spring-core-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-jcl\5.2.7.RELEASE\spring-jcl-5.2.7.RELEASE.jar com.example.io.serializable.TestSerializable
2 序列化成功
3 Book(id=1, name=從大爆炸到黑洞, price=100.0)
4 
5 Process finished with exit code 0

 

2、先序列化,然后刪除(修改)對象中某一個屬性,再進行反序列化

  刪除一個屬性后的實體類

1 @Data
2 public class Book implements Serializable{
3 
4     private static final long serialVersionUID = -1858406188231479520L;
5 
6     private int id;
7     private String name;
8     //private Double price;
9 }

 

  反序列化

1 D:\Work\Jdk\bin\java.exe "-javaagent:D:\Work\Idea\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=56290:D:\Work\Idea\IntelliJ IDEA 2019.3.4\bin" -Dfile.encoding=UTF-8 -classpath D:\Work\Jdk\jre\lib\charsets.jar;D:\Work\Jdk\jre\lib\deploy.jar;D:\Work\Jdk\jre\lib\ext\access-bridge-64.jar;D:\Work\Jdk\jre\lib\ext\cldrdata.jar;D:\Work\Jdk\jre\lib\ext\dnsns.jar;D:\Work\Jdk\jre\lib\ext\jaccess.jar;D:\Work\Jdk\jre\lib\ext\jfxrt.jar;D:\Work\Jdk\jre\lib\ext\localedata.jar;D:\Work\Jdk\jre\lib\ext\nashorn.jar;D:\Work\Jdk\jre\lib\ext\sunec.jar;D:\Work\Jdk\jre\lib\ext\sunjce_provider.jar;D:\Work\Jdk\jre\lib\ext\sunmscapi.jar;D:\Work\Jdk\jre\lib\ext\sunpkcs11.jar;D:\Work\Jdk\jre\lib\ext\zipfs.jar;D:\Work\Jdk\jre\lib\javaws.jar;D:\Work\Jdk\jre\lib\jce.jar;D:\Work\Jdk\jre\lib\jfr.jar;D:\Work\Jdk\jre\lib\jfxswt.jar;D:\Work\Jdk\jre\lib\jsse.jar;D:\Work\Jdk\jre\lib\management-agent.jar;D:\Work\Jdk\jre\lib\plugin.jar;D:\Work\Jdk\jre\lib\resources.jar;D:\Work\Jdk\jre\lib\rt.jar;D:\Personal\JavaProject\io\target\classes;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.1.RELEASE\spring-boot-starter-data-jdbc-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.1.RELEASE\spring-boot-starter-jdbc-2.3.1.RELEASE.jar;D:\Work\Maven\repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\Work\Maven\repository\org\springframework\spring-jdbc\5.2.7.RELEASE\spring-jdbc-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-jdbc\2.0.1.RELEASE\spring-data-jdbc-2.0.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-relational\2.0.1.RELEASE\spring-data-relational-2.0.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\data\spring-data-commons\2.3.1.RELEASE\spring-data-commons-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-tx\5.2.7.RELEASE\spring-tx-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-context\5.2.7.RELEASE\spring-context-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-aop\5.2.7.RELEASE\spring-aop-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-expression\5.2.7.RELEASE\spring-expression-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-beans\5.2.7.RELEASE\spring-beans-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter\2.3.1.RELEASE\spring-boot-starter-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot\2.3.1.RELEASE\spring-boot-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.1.RELEASE\spring-boot-autoconfigure-2.3.1.RELEASE.jar;D:\Work\Maven\repository\org\springframework\boot\spring-boot-starter-logging\2.3.1.RELEASE\spring-boot-starter-logging-2.3.1.RELEASE.jar;D:\Work\Maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\Work\Maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\Work\Maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\Work\Maven\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\Work\Maven\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\Work\Maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\Work\Maven\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\Work\Maven\repository\org\springframework\spring-core\5.2.7.RELEASE\spring-core-5.2.7.RELEASE.jar;D:\Work\Maven\repository\org\springframework\spring-jcl\5.2.7.RELEASE\spring-jcl-5.2.7.RELEASE.jar com.example.io.serializable.TestSerializable
2 Book(id=1, name=從大爆炸到黑洞)
3 
4 Process finished with exit code 0

 

 

 總結:

(1)對實體進行implement Serializable,表示該對象可以進行序列化;

(2)只進行implement Serializable,每次進行序列化時會自動生成一個serialVersionUID保證序列化的進行,

  在實體對象沒有改變過的前提下,可以進行反序列化,如果對象屬性改變過,反序列化時再次生成的UID和序列化時生成的UID不同無法進行反序列化;

(3)在進行implement Serializable后,加上private static final long serialVersionUID = xxxL; 可保證序列化之后,即使對實體對象做出了改變仍可以進行反序列化。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM