kryo


 
測試kryo與jdk的ObjectOutputStream

 

 

kryo常用設置

InstantiatorStrategy即初始化策略,默認kryo在反序列化對象時需要對象的類有一個零參數構造器,該構造器可以是private的,kryo通過反射調用該構造器來實例化對象。如果沒有這樣一個構造器,就需要使用kryo.setInstantiatorStrategy(new StdInstantiatorStrategy())了,該策略通過jvm api創建對象,這會創建一個完全空的對象(即不執行任何代碼中的初始化工作),如果對象在實例化時需要一些初始化操作(比如在構造代碼塊中執行一些計算邏輯),這種策略就不可行了。
比較好的策略是kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));,即先嘗試通過零參數構造實例化對象,如果類中沒有零參數構造器,則會使用StdInstantiatorStrategy策略。
 
References即引用,對A對象序列化時,默認情況下kryo會在每個成員對象第一次序列化時寫入一個數字,該數字邏輯上就代表了對該成員對象的引用,如果后續有引用指向該成員對象,則直接序列化之前存入的數字即可,而不需要再次序列化對象本身。這種默認策略對於成員存在互相引用的情況較有利,否則就會造成空間浪費(因為沒序列化一個成員對象,都多序列化一個數字),通常情況下可以將該策略關閉,kryo.setReferences(false);
 
Registration即注冊,kryo在序列化對象時,首先會序列化其類的全限定名,由於我們通常序列化的對象都是有限范圍內的類的實例,這樣重復序列化同樣的類的全限定名是低效的。通過注冊kryo可以將類的全限定名抽象為一個數字,即用一個數字代表全限定名,這樣就要高效一些。kryo.register(SomeClass.class);,注冊方法的完整簽名為public Registration register (Class type, Serializer serializer, int id),我們通常只需要使用其重載方法即可public Registration register (Class type),serializer和id在kryo內部會指定。
 
PS:使用kryo序列化時,可以使用transient關鍵字忽略某字段。
 

序列化方法

kryo大體有三種序列化方法,每種方式都有其優勢和劣勢。
1,kryo.writeObject,這種方法只會序列化對象實例,而不會記錄對象所屬類的任何信息。優勢是最節省空間,劣勢是在反序列化時,需要提供類作為模板才能順利反序列。反序列化時使用readObject。
2,直接kryo.writeClassAndObject,這種方法會先將對象所屬類的全限定名序列化,然后再依次序列化對象實例的成員。優勢是完全動態序列化,整個kryo周期都不需要提供類信息。反序列化時使用readClassAndObject
3,先注冊,再kryo.writeClassAndObject,這種方式時最理想的,其結合了前兩種優勢,又有效規避了劣勢,事先將需要序列化的類注冊給kryo(此時類和唯一id綁定),之后使用writeClassAndObject序列化時,只會序列化注冊id,而不會序列化類的全限定名了,這樣大大節省了空間(通常只比writeObject多一個字節)。反序列化時使用readClassAndObject。注意序列化和反序列的kryo的注冊信息應當保持一致。
 

Example

 1 public class Simple {  
 2  private String name;  
 3  private int age;  
 4  
 5  
 6  public String getName() {  
 7    return name;  
 8  }  
 9  
10   public void setName(String name) {  
11     this.name = name;  
12   }  
13   
14   public int getAge() {  
15     return age;  
16   }  
17   
18   public void setAge(int age) {  
19     this.age = age;  
20   }  
21   
22   static Simple getSimple() {  
23     Simple simple = new Simple();  
24     simple.setAge(10);  
25     simple.setName("zhang3");  
26     return simple;  
27   }  
28 }

 

1 Kryo kryo = new Kryo();  
2 kryo.setReferences(false);  
3 kryo.setRegistrationRequired(false);  
4 kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());  
5 Output output = new Output(new FileOutputStream("file.bin"));
6 kryo.writeClassAndObject(output, Simple.getSimple());  
7 output.close();

 

 

紅色框內,第一個字節代表classId,也就是kryo中注冊的id,01表示未注冊,第二個字節代表nameId;

綠色框內為類的全限定名;

紫色框內,唯一的一個字節14表示age屬性值10(cryo為了優化存儲,定義了自己的映射關系);

粉色框內表示字符串“zhang3”,其中字符串“zhang”可以與asc碼一一對應,最后一個字符“3”這里為B3就有些匪夷所思了,與14表示10類似,kryo對字符串也做了優化,這樣可以省去表示長度的字節序列(具體優化策略就不探究了)。

如果序列化時,Sample中字段的順序是age、name,反序列化時,Sample中字段的順序是name、age,這樣會不會有問題呢?

不會有問題,kryo在序列化、反序列前對字段進行了排序,kryo的序列化、反序列化順序與字段聲明順序無關。


免責聲明!

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



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