为什么如此高效?解密kryo各个数据类型的序列化编码机制,强( 六 )
DefaultClassResolver#readName
protected Registration readName (Input input) { int nameId = input.readVarInt(true);if (nameIdToClass == null) nameIdToClass = new IntMap(); Class type = nameIdToClass.get(nameId);if (type == null) {// Only read the class name the first time encountered in object graph.String className = input.readString();type = getTypeByName(className);if (type == null) {try {type = Class.forName(className, false, kryo.getClassLoader());} catch (ClassNotFoundException ex) {if (WARN) warn("kryo", "Unable to load class " + className + " with kryo's ClassLoader. Retrying with current..");try {type = Class.forName(className);} catch (ClassNotFoundException e) {throw new KryoException("Unable to find class: " + className, ex);}}if (nameToClass == null) nameToClass = new ObjectMap();nameToClass.put(className, type);}nameIdToClass.put(nameId, type);if (TRACE) trace("kryo", "Read class name: " + className); } else {if (TRACE) trace("kryo", "Read class name reference " + nameId + ": " + className(type)); } return kryo.getRegistration(type);}
首先读取类的id , 因为在序列化类时 , 如果序列化字符串时 , 首先先用变长int存储类型的nameId , 然后再序列化类的全路径名 , 这样在一次反序列化时 , 第一次序列化时 , 将全列的全路径使用Class.forName实例化对象后 , 然后存储在局部方法缓存中(IntMap)中 , 在这一次序列化时再碰到同类型时 , 则根据id则可以找到对象 。
类实例序列化总结:
类实例序列化需求:序列化类的全路径名 , 反序列化时根据Class.forName生成对应的实例 。
kryo序列化Class实例的编码规则:
- 如果为null , 用变长int , 实际使用1个字节 , 存储变量0 。
- 如果该类通过类注册机制注册到kryo时 , 则序列化(nameId + 2) , 用变长int存储 。
- 如果该类未通过类注册机制注册到kryo , 在一次序列化过程中(包含级联)时 , 类型第一次出现时 , 会分配一个nameId , 将nameId + type全路径序列化 , 后续再出现该类型 , 则只序列化nameId即可 。
14 , 枚举类型Enum序列化实现类为:DefaultSerializers $ EnumSerializer
static public class EnumSerializer extends Serializer {{setImmutable(true);setAcceptsNull(true);}private Object[] enumConstants;public EnumSerializer (Class extends Enum> type) {enumConstants = type.getEnumConstants();if (enumConstants == null) throw new IllegalArgumentException("The type must be an enum: " + type);}public void write (Kryo kryo, Output output, Enum object) {if (object == null) {output.writeVarInt(NULL, true);return;}output.writeVarInt(object.ordinal() + 1, true);}public Enum read (Kryo kryo, Input input, Class type) {int ordinal = input.readVarInt(true);if (ordinal == NULL) return null;ordinal--;if (ordinal < 0 || ordinal > enumConstants.length - 1)throw new KryoException("Invalid ordinal for enum \"" + type.getName() + "\": " + ordinal);Object constant = enumConstants[ordinal];return (Enum)constant;} }
枚举类型序列化(支持null):- 如果为null , 则使用变长int , 实际用一个字节存储0 。
- 如果不为null , 使用变长int , 存储object.ordinal()+ 1 , 也就是序列化该值在枚举类型常量中中下标 , 由于0代表为空 , 则下标从1开始 。
15 , EnumSet类型序列化实现类为:DefaultSerializers $ EnumSetSerializer
static public class EnumSetSerializer extends Serializer { public void write (Kryo kryo, Output output, EnumSet object) {Serializer serializer;if (object.isEmpty()) {// @1EnumSet tmp = EnumSet.complementOf(object);// @2if (tmp.isEmpty()) throw new KryoException("An EnumSet must have a defined Enum to be serialized.");serializer = kryo.writeClass(output, tmp.iterator().next().getClass()).getSerializer();// @3} else {serializer = kryo.writeClass(output, object.iterator().next().getClass()).getSerializer();}output.writeInt(object.size(), true);// @4for (Object element : object)// @5serializer.write(kryo, output, element);} public EnumSet read (Kryo kryo, Input input, Class type) {Registration registration = kryo.readClass(input);EnumSet object = EnumSet.noneOf(registration.getType());Serializer serializer = registration.getSerializer();int length = input.readInt(true);for (int i = 0; i < length; i++)object.add(serializer.read(kryo, input, null));return object; } public EnumSet copy (Kryo kryo, EnumSet original) {return EnumSet.copyOf(original); }}
- 看不上|为什么还有用户看不上华为Mate40系列来看看内行人怎么说
- 设置|iPhone拍照小技巧:保留常用设置更高效
- 制药领域|为什么AI制药这么火,为什么是现在?
- 手机壳里头|为什么要在手机壳里面夹钱?10个有9个不懂,我才知道大有讲究
- 短视频|全球最火APP?抖音爆火背后离不开这几剂“猛药”为什么抖音能够这么火?
- 电商快递|包邮不香吗,为什么还有人加49元让小哥穿西装专车送快递?
- 团队|为什么项目管理非常重要?
- 猫腻|为什么拼多多上商品价格那么便宜还包邮?有什么猫腻?看完明白了
- 加拿大|上演戏剧性一幕!iPhone12最新售价确定,苹果也没想到降价如此快
- 刷机|前几年满大街的“刷机”服务去哪里了,为什么大家都不爱刷机了?