Java序列化接口Serializable接口的作用总结
一.Java序列化接口Serializable的作用:
一個對象有對應的一些屬性,把這個對象保存在硬盤上的過程叫做”持久化”. ?
對象的默認序列化機制寫入的內(nèi)容是:對象的類,類簽名,以及非瞬態(tài)和非靜態(tài)字段的值。(因為靜態(tài)static的東西在方法區(qū).)
序列化能把堆內(nèi)存中的對象的生命周期延長,做持久化操作.當下次再需要這個對象的時候,我們不用new了,直接從硬盤中讀取就可以了.(存儲到硬盤是一個文件,不需要我們?nèi)ソ馕?如果用記事本打開解析會出現(xiàn)亂碼,解析要用特定的方式,不用我們管. 我們只需要讀取). ?把對象存儲到硬盤上的一個文件中,這個文件的標準擴展名是(.object).
什么樣的數(shù)據(jù)會進行序列化到硬盤進行持久化?
①在很多框架中就會有這種.object結(jié)尾的文件,因為很多對象都不創(chuàng)建,創(chuàng)建起來太麻煩,直接讀取,而且有些對象的值你不知道,框架封存在.object文件中,直接讀取這個文件中的這個值就行了,不需要傳這個值.
在搞web開發(fā)的時候一些類就需要實現(xiàn)序列化接口,因為服務器就會對你的對象進行臨時本地存儲.它怕服務器崩了的以后,你的會話都被消失了.所以存儲在了硬盤上,你重新啟動服務器會恢復之前的會話,恢復對象,你之前運行的東西都在.
?
②對某些特點的對象,比如數(shù)據(jù)庫連接對象,存儲特定數(shù)據(jù)的對象 ,這樣對象你不想創(chuàng)建他們,想存儲起來,讓他們的生命周期延長,可以把他們放在硬盤當中.每次系統(tǒng)啟動的時候都到.object中讀取對象和里面的數(shù)據(jù),這個時候就可以把他們序列化來完成.
二.具體舉例:
Person.java
1 import java.io.Serializable;2 /*3 * Serializable:用于給被序列化的類加入ID號。4 * 用于判斷類和對象是否是同一個版本。 5 */6 public class Person implements Serializable/*標記接口*/ {7 /**8 * transient:非靜態(tài)數(shù)據(jù)不想被序列化可以使用這個關(guān)鍵字修飾。 9 */ 10 private static final long serialVersionUID = 9527l; 11 // private transient String name; 12 private String name; 13 // private static int age; 14 private int age; 15 16 public Person(String name, int age) { 17 super(); 18 this.name = name; 19 this.age = age; 20 } 21 public String getName() { 22 return name; 23 } 24 public void setName(String name) { 25 this.name = name; 26 } 27 public int getAge() { 28 return age; 29 } 30 public void setAge(int age) { 31 this.age = age; 32 } 33 }ObjectStreamDemo.java
1 public class ObjectStreamDemo {2 /**3 * @param args4 * @throws IOException 5 * @throws ClassNotFoundException 6 */7 public static void main(String[] args) throws IOException, ClassNotFoundException {8 //writeObj();9 readObj(); 10 } 11 public static void readObj() throws IOException, ClassNotFoundException { 12 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object")); 13 //對象的反序列化。 14 Person p = (Person)ois.readObject(); 15 System.out.println(p.getName()+":"+p.getAge()); 16 ois.close(); 17 } 18 19 public static void writeObj() throws IOException, IOException { 20 21 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object")); 22 //對象序列化。 被序列化的對象必須實現(xiàn)Serializable接口。 23 oos.writeObject(new Person("小強",30)); 24 oos.close(); 25 } 26 }?
上面的例子中當你一開始對這個person類進行序列化的時候用的是private類型序列化的,但是你在反序列化之前,把這個private改成了public.這樣反序列化讀取的時候就會報出異常.
Exception in thread "main" java.io.InvalidClassException: cn.itcast.serializable.Person; local class incompatible: stream classdesc serialVersionUID = 9527, local class serialVersionUID = 7915096815468332737就是關(guān)于前后這個Person類的版本號不統(tǒng)一.如果加上設(shè)定一個版本號,那么經(jīng)過上面的修改也是可以反序列化的.
可能拋出的錯誤?@throws?ClassNotFoundException
如果只有obj.object 這個文件能不能把其中的對象Person取出來,因為任何對象在堆內(nèi)存中創(chuàng)建都必須依賴于該對象所屬的類文件(class文件),如果僅僅給了obj.object,這個里面有Person對象的字節(jié)碼,可是取出的時候你內(nèi)存中并沒有Person.class文件,沒有,所以取不出來,所以必須要有obj.object文件和Person.class文件.(所以有一個ClassNotFound異常)
關(guān)于程序中的類 ObjectInputStream和ObjectOutputStream?
ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本數(shù)據(jù)和對象進行反序列化(意思就是ObjectInputStream只能讀取ObjectOutputStream的)
ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一起使用時,可以為應用程序提供對對象的持久存儲。
關(guān)于SerializableID
SerializableID號是根據(jù)類的特征和類的簽名算出來的.為什么ID號那么長,是因為為了避免重復.所以Serializable是給類加上id用的. 用于判斷類和對象是否是同一個版本。
如果可序列化類未顯式聲明 serialVersionUID,則序列化運行時將基于該類的各個方面計算該類的默認 serialVersionUID 值. 原因是計算默認的 serialVersionUID 對類的詳細信息具有較高的敏感性,根據(jù)編譯器實現(xiàn)的不同可能千差萬別,這樣在反序列化過程中可能會導致意外的?InvalidClassException。
序列化接口的i
序列化Serializable的方式特別簡單 實現(xiàn)Serializable接口,再在類中聲明如下這一個屬性即可。
private static final long serialVersionUID = -3928832861296252415L;
Serializable序列化的工作機制:
序列化的時候系統(tǒng)會把當前類的serialVersionUID 寫入序列化的文件中(也可能是其他中介),當反序列化的時候系統(tǒng)會去檢測文件中的serialVersionUID?,看它是否和當前類的serialVersionUID 一致,如果一致就說明序列化的類的版本和當前類的版本是相同的,這個時候可以成功反序列化,否則就說明當前類和序列化的類相比發(fā)生了某些變換,比如成員變量的數(shù)量,類型可能發(fā)生了改變,這個時候就會拋異常,反序列化失敗。
serialVersionUID作用:?
序列化時為了保持版本的兼容性,即在版本升級時反序列化仍保持對象的唯一性。?
那么serialVersionUID 是如何生成,生成規(guī)則是怎么樣的呢?
默認情況下,也就是不聲明serialVersionUID 屬性情況下,系統(tǒng)會按當前類的成員變量計算hash值并賦值給serialVersionUID 。
所以,結(jié)論就出來了。聲明serialVersionUID ,可以很大程度上避免反序列化過程的失敗。比如當版本升級后,我們可能刪除了某個成員變量,也可能增加了一些新的成員變量,這個時候我們的反序列化依然能夠成功,程序依然能夠最大程度地恢復數(shù)據(jù),相反,如果不指定serialVersionUID ,程序就會掛掉。
?
如果類結(jié)構(gòu)發(fā)生了非常規(guī)性改變,比如修改了類名,類型等,這個時候盡管serialVersionUID 驗證通過了,但是反序列化過程
還是會失敗,因為類結(jié)構(gòu)有了毀滅性的改變。
總結(jié)
以上是生活随笔為你收集整理的Java序列化接口Serializable接口的作用总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据仓库、数据湖、流批一体
- 下一篇: spring同类调用事务不生效-原因及三