zoukankan      html  css  js  c++  java
  • 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的序列化、反序列化顺序与字段声明顺序无关。

  • 相关阅读:
    四则运算2之单元测试
    四则运算2之小学二年级
    四则运算2--思路
    大道至简---读书随笔
    随机30道四则运算
    读书计划
    软件工程课堂作业(七)——电梯调度之需求规格说明书
    《梦断代码Dreaming In Code》阅读笔记(二)
    软件工程课堂作业(六)——结对开发(二)
    软件工程课堂作业(五)——终极版随机产生四则运算题目(C++)
  • 原文地址:https://www.cnblogs.com/holoyong/p/7420880.html
Copyright © 2011-2022 走看看