java自定義序列化的具體使用
1.問題引出
在某些情況下,我們可能不想對于一個對象的所有field進行序列化,例如我們銀行信息中的設計賬戶信息的field,我們不需要進行序列化,或者有些field本省就沒有實現(xiàn)Serializable接口。
java中的序列化是遞歸序列化,也就是你的field的引用類型中也有field可以被序列化,那么就會在序列化當前對象的時候,一同序列化
2.解決辦法
使用transient(瞬變現(xiàn)象;過往旅客;候鳥)關鍵字來修飾,該關鍵字只能修飾屬性,這樣在序列化的時候,這個屬性就會用默認值,例如int類型用0,引用對象用null;
但是使用transient關鍵字修飾的field雖然簡單方便,但是會被完全隔離在序列化機制之外,這樣導致在反序列化回復java對象的時候,無法取得該field的值。
因此我們可以使用自定義序列化機制,可以讓程序控制如何序列化各field,甚至完全不序列化某些field(這樣就與transient相同),在序列化和反序列化過程中需要特殊處理的類應該提供如下特殊簽名的方法,這些特殊的方法用以實現(xiàn)自定義的序列化
private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in)throws IOException,ClassNotFoundException; private void readObejctNoData()throws ObejctStreamException;
熱愛你所寫的每一行的代碼
writeObject()方法負責寫入特定類的實例狀態(tài),通過重寫這個方法,程序員可以完全獲得對序列化機制的控制,可以自主決定那些field需要序列化,需要怎么序列化,默認情況(函數(shù)體為空)該方法會調用out.defaultWriteObject來保存java對象的各field,從而達到實現(xiàn)序列化java對象狀態(tài)的目的
readObject負責從流中讀取并且回復對象的field,通過重寫該方法,程序員,可以獲得對反序列化機制的控制,對于反序列化各個field的順序應該和序列化各個field的順序相同。
至于當序列化流不完整時,readObjectNoData可以正確的初始化反序列化的對象,例如接收方接收到的序列化流殘缺,或者序列化版本不同,則使用readObjectNoData來默認的初始化。
例子(對于person的改寫):
class Person implements Serializable { private String name; private int age; public Person(String name,int age) { this.name=name; this.age=age; } //自動生成的Get和Set方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } private void writeObject(ObjectOutputStream out) throws IOException { //將名字翻轉之后寫入二進制流 out.writeObject(new StringBuffer(this.name).reverse()); out.writeInt(this.age); } private void readObject(ObjectInputStream in)throws IOException,ClassNotFoundException { this.name=((StringBuffer)in.readObject()).reverse().toString(); //會拋出異常,因為這里的這樣寫法導致同 this.age=in.readInt(); } }
應該提醒的是,這個自定義的功能十分強大
另外一種替換性的改寫:
//注意:這個方法由序列化機制調用,只要該方法存在就,它的訪問控制符就可以為private protected package-private中的任意一種 private Object writeReplace() throws ObjectStreamException { ArrayList<Object> list=new ArrayList<>(); list.add(name); list.add(age); //我們這里返回ArrayList return list; }
序列化機制保證在序列化某個對象之前,先調用該對象的writeReplace方法,如果該方法返回另外一個java對象,系統(tǒng)就轉換為序列化writeReplace的返回結果。(ps:如果這個返回結果也有writeReplace方法的話,就繼續(xù)遞歸替代,直到沒有替換)
相應與writeReplace相對的有一個readResolve方法,這個方法保護性的賦值整個對象,這里就不展開討論了。
3.另外一種自定義序列化機制(介紹Externalizable)
Java還提供了另一種序列化機制,這種序列化方式完全由程序員決定存儲和恢復對象數(shù)據。要實現(xiàn)該目標,Java類必須實現(xiàn)Externalizable接口,該接口里定義了如下兩個方法。
- void readExternal(ObjectInput in):需要序列化的類實現(xiàn)readExternal()方法來實現(xiàn)反序列化。該方法調用DataInput(它是ObjectInput的父接口)的方法來恢復基本類型的Field值,調用ObjectInput的readObject()方法來恢復引用類型的Field值。
- void writeExternal(ObjectOutput out):需要序列化的類實現(xiàn)writeExternal()方法來保存對象的狀態(tài)。該方法調用DataOutput(它是ObjectOutput的父接口)的方法來保存基本類型的Field值,調用ObjectOutput的writeObject()方法來保存引用類型的Field值。
具體的實現(xiàn)方式與上面自定義Serializable接口的實現(xiàn)類的序列化是相同的操作,這里就不闡述了,下面圖是二者的比較。
到此這篇關于java自定義序列化的具體使用的文章就介紹到這了,更多相關java自定義序列化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring Boot Actuator未授權訪問漏洞的問題解決
Spring Boot Actuator 端點的未授權訪問漏洞是一個安全性問題,可能會導致未經授權的用戶訪問敏感的應用程序信息,本文就來介紹一下解決方法,感興趣的可以了解一下2023-09-09SpringBoot實現(xiàn)動態(tài)增刪啟停定時任務的方式
在spring?boot中,可以通過@EnableScheduling注解和@Scheduled注解實現(xiàn)定時任務,也可以通過SchedulingConfigurer接口來實現(xiàn)定時任務,但是這兩種方式不能動態(tài)添加、刪除、啟動、停止任務,本文給大家介紹SpringBoot實現(xiàn)動態(tài)增刪啟停定時任務的方式,感興趣的朋友一起看看吧2024-03-03mybatis查詢實現(xiàn)返回List<Map>類型數(shù)據操作
這篇文章主要介紹了mybatis查詢實現(xiàn)返回List<Map>類型數(shù)據操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11Java郵件發(fā)送程序(可以同時發(fā)給多個地址、可以帶附件)
不錯的功能比較齊全的郵件發(fā)送程序源碼2008-07-07SpringBoot詳解整合Spring?Boot?Admin實現(xiàn)監(jiān)控功能
這篇文章主要介紹了SpringBoot整合Spring?Boot?Admin實現(xiàn)服務監(jiān)控,內容包括Server端服務開發(fā),Client端服務開發(fā)其中Spring?Boot?Admin還可以對其監(jiān)控的服務提供告警功能,如服務宕機時,可以及時以郵件方式通知運維人員,感興趣的朋友跟隨小編一起看看吧2022-07-07SpringBoot+docker環(huán)境變量配置詳解
這篇文章主要介紹了SpringBoot+docker環(huán)境變量配置詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10