java对象序列化作用_Java学习之——理解对象序列化
Java的對(duì)象序列化就是把對(duì)象寫入到輸出流中,用來存儲(chǔ)或傳輸;反序列化就是從輸入流中讀取對(duì)象。簡(jiǎn)單的來說是指將那些實(shí)現(xiàn)了Serializable接口的對(duì)象轉(zhuǎn)換成一個(gè)字節(jié)序列,并能夠在以后將這個(gè)字節(jié)序列完全恢復(fù)為原來的對(duì)象。
要序列化一個(gè)對(duì)象首先要?jiǎng)?chuàng)造某些OutputStream對(duì)象(如FileOutputStream、ByteArrayOutputStream等),然后將其封裝在一個(gè)ObjectOutputStream對(duì)象中,在調(diào)用writeObject()方法即可序列化一個(gè)對(duì)象;而反序列化的過程需要?jiǎng)?chuàng)造InputStream對(duì)象(如FileInputstream、ByteArrayInputStream等),然后將其封裝在ObjectInputStream中,在調(diào)用readObject()即可。注意 對(duì)象的序列化是基于字節(jié)的不能使用基于字符的流。
實(shí)現(xiàn)對(duì)象的序列化有兩種方式:(1)實(shí)現(xiàn)Serializable接口 (2)實(shí)現(xiàn)Externalible接口
一、序列化
1.第一種方式——實(shí)現(xiàn)Serializable接口。該接口僅為標(biāo)記接口,不包含任何方法定義,表示實(shí)現(xiàn)了該接口的類可以被序列化,且實(shí)現(xiàn)該接口的類的所有子類都可以被序列化。而且實(shí)現(xiàn)了該接口的類默認(rèn)為自動(dòng)序列化,即對(duì)象中的所有字段都將被可序列化。但是有時(shí)候我們需要對(duì)某些字段不進(jìn)行自動(dòng)序列化(因?yàn)樾蛄谢瘯?huì)曝光信息),這時(shí)候我們就需要transient關(guān)鍵字(該關(guān)鍵字只能和Serializable對(duì)象一起使用)。被該關(guān)鍵字修飾的字段在自動(dòng)序列化的過程中將不會(huì)被序列化。除了默認(rèn)的自動(dòng)序列化,我們也可以手動(dòng)控制序列化過程,手動(dòng)序列化甚至可以實(shí)現(xiàn)將被transient關(guān)鍵字修飾的字段序列化。要想實(shí)現(xiàn)手動(dòng)序列化需要在實(shí)現(xiàn)了Serializable接口的類中添加兩個(gè)私有的方法writeObject()和readObject(),在這兩個(gè)方法中控制字段的序列化。
private void writeObject(ObjectOutputStream oos)throws IOException{
oos.defaultWriteObject();
oos.writeObject(password);
}第一行代碼是序列化所有非transient字段,必須是該方法的第一個(gè)操作
第二行代碼是序列化transient字段
private void readObject(ObjectInputStream ois)throws IOException,ClassNotFoundException{
ois.defaultReadObject();
password = (String)ois.readObject();
}
第一行代碼是反序列化所有非transient和非靜態(tài)字段,必須是該方法的第一個(gè)操作
第二行代碼是反序列化transient字段
這兩個(gè)方法會(huì)在序列化、反序列化的過程 中被自動(dòng)調(diào)用。且不能關(guān)閉流,否則會(huì)導(dǎo)致序列化操作失敗。
2.第二種方式——實(shí)現(xiàn)Externalible接口。實(shí)現(xiàn)該接口需要定義一個(gè)默認(rèn)的構(gòu)造函數(shù),否則將會(huì)拋出java.io.InvalidClassException異常。此外還需要定義兩個(gè)方法writeExternal()和readExternal()來控制序列化字段。
public void writeExternal(ObjectOutput out)throws IOException{
out.writeObject(name);
out.writeObject(password);
}
public void readExternal(ObjectIntput in)throws IOException,ClassNotFoundException{
name = in.readObject();
password = in.readObject();
}如果通過序列化將一個(gè)對(duì)象持久化寫入到文件中應(yīng)當(dāng)注意以下情況:
(1)我們知道 FileOutputStream類有一個(gè)帶有兩個(gè)參數(shù)的重載Constructor——FileOutputStream(String,boolean)。若第二個(gè)參數(shù)為true且String代表的文件存在,那么將把新的內(nèi)容寫到原來文件的末尾而非重寫這個(gè)文件,這里我們不能用這個(gè)版本的構(gòu)造函數(shù),也就是說我們必須重寫這個(gè)文件,否則在讀取這個(gè)文件反序列化的過程中就會(huì)拋出異常,導(dǎo)致只有我們第一次寫到這個(gè)文件中的對(duì)象可以被反序列化,之后程序就會(huì)出錯(cuò)。
(2)若一個(gè)類的字段有引用對(duì)象,那么在序列化該類的時(shí)候不僅該類要實(shí)現(xiàn)Serializable接口,這個(gè)引用類型也要實(shí)現(xiàn)Serializable接口。但有時(shí)我們并不需要對(duì)這個(gè)引用類型進(jìn)行序列化,此時(shí)就需要使用transient關(guān)鍵字來修飾該引用類型保證在序列化的過程中跳過該引用類型。
(3)注意序列化操作保存的是對(duì)象的狀態(tài),靜態(tài)字段是類的狀態(tài)而不是對(duì)象的狀態(tài),所以不能序列化。
(4) 序列化前后對(duì)象的地址不同了,但是內(nèi)容是一樣的,而且對(duì)象中包含的引用也相同。換句話說,通過序列化操作,我們可以實(shí)現(xiàn)對(duì)任何可Serializable對(duì)象的”深度復(fù)制(deep copy)"——這意味著我們復(fù)制的是整個(gè)對(duì)象網(wǎng),而不僅僅是基本對(duì)象及其引用。對(duì)于同一流的對(duì)象,他們的地址是相同,說明他們是同一個(gè)對(duì)象,但是與其他流的對(duì)象地址卻不相同。也就說,只要將對(duì)象序列化到單一流中,就可以恢復(fù)出與我們寫出時(shí)一樣的對(duì)象網(wǎng),而且只要在同一流中,對(duì)象都是同一個(gè)。
(5)如果父類沒有實(shí)現(xiàn)Serializable接口,但其子類實(shí)現(xiàn) 了此接口,那么 這個(gè)子類是可以序列化的,但是在反序列化的過程 中會(huì)調(diào)用 父類 的無參構(gòu)造函數(shù),所以在其直接父類(注意是直接父類)中必須有一個(gè)無參的構(gòu)造函數(shù)。
(6)序列化輸出過程跟蹤寫入流的對(duì)象,試圖將同一個(gè)對(duì)象寫入流時(shí),不會(huì)導(dǎo)致該對(duì)象被復(fù)制,而只是將一個(gè)句柄寫入流,該句柄指向流中相同對(duì)象的第一個(gè)對(duì)象出現(xiàn)的位置。為了避免這種情況,方法是在writeObject()之前調(diào)用out.reset()方法,這個(gè)方法的作用是清除流中保存的寫入對(duì)象的記錄。
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的java对象序列化作用_Java学习之——理解对象序列化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java8函数式编程 视频_快速掌握Ja
- 下一篇: toto马桶水箱一直流水怎么修视频?