为什么如此高效?解密kryo各个数据类型的序列化编码机制,强( 三 )

正确表示长度的编码规则(int) , 第8位(高位)表示字符串的编码 , 第7位(高位)表示是否还需要重新读取一个字节 , 也就是结束标记 , 1表示未结束 , 0表示结束 。 一个字节共8位 , 只有低6位放置了数据 , varint采取的是小端序列 。
代码@ 6:如果当前缓存区有足够的空间 , 先尝试将字符串中单字节数据写入到缓冲区中 , 碰到第一个非单字节字符时 , 结束 。
代码@ 7:将剩余空间写入缓存区 , 其实现方法:Output#writeString_slow(value , charCount , charIndex)
输出#writeString_slow
private void writeString_slow (CharSequence value, int charCount, int charIndex) {for (; charIndex < charCount; charIndex++) {// @1if (position == capacity) require(Math.min(, charCount - charIndex));// @2int c = value.charAt(charIndex);// @3if (c <= 0x007F) {// @4buffer[position++] = (byte)c;} else if (c > 0x07FF) {// @5buffer[position++] = (byte)(0xE0 | c >> 12require(2);buffer[position++] = (byte)(0x80 | c >> 6buffer[position++] = (byte)(0x80 | c} else {// @6buffer[position++] = (byte)(0xC0 | c >> 6require(1);buffer[position++] = (byte)(0x80 | c}} }代码@ 1:循环遍历字符的字符 。
代码@ 2:如果当前缓存区已经写满 , 尝试申请(capacity与charCount-charIndex)的替换 , 此处无需担心字符不是单字节申请charCount-charIndex空间不足的问题 , 后面我们会详细分析require方法 , 字节不足时会触发缓存区扩容或刷写到流中 , 再重复利用缓存区 。
代码@ 3:int c = value.charAt(charIndex); 将字符类型转换为int类型 , 一个中文字符对应一个int数字 , 这是因为java使用unicode编码 , 每个字符占用2个字节 , char向int类型转换 , 就是将2个字节的字节编码 , 转换成对应的二进制 , 然后用10个二进制表示的数字 。
代码@ 4:如果值小于等0x7F(127) , 直接存储在1个字节中 , 此时高位4个字节的范围在(0-7) 。 ] 。
代码@ 5:如果值大于0x07FF(二进制0000 0111 1111 1111) , 第一个大于0x7F的变量(0000 1000 0000 0000) , 即2 ^ 12 , 数据有效位至少12位 , 使用3字节来存储 , 具体存储方式为:
1)buffer [0]:buffer [position ++] =(byte)(0xE0 | c >> 12&0x0F); 首先将c右移12位再与0x0F进行与操作 , 其意义就是先提取c的第16-13(4位的值) , 并与0xE0取或 , 最终的数值0xE(16-13)位的值 , 从输入中读取字符串可以研磨 , 是根据0xE0作为存储该字符需要3个字节的依据 , 并且只取16-13位的值作为其高位的有效位 , 从而字符编码的值 , 不会超过0XFFFF , 也就是两个字节(正好与java unicode编码吻合) 。
2)buffer [1]:存储第12-7(共6位) , c >> 6&0x3F , 然后与0X80进行或 , 高位设置为1 , 表示UTF-8编码 , 其实再反序列化时 , 这个高位设置为1 , 未有实际作用 。
3)buffer [2]:存储第6-1(共6位) , 0x80 | c&0x3F , 同样高位置1 。
2.2字符串反序列化(byte [] ----> String)在讲解反序列化时 , 总结一下字符串序列化的编码规则
String序列化规则:String序列化的整体结构为length +内容 , 注意 , 这里的length不是内容字节的长度 , 而是String字符的长度 。

  1. 如果是null , 则用1个字节表示 , 其二进制为1000 0000 。
  2. 如果是“”空字符串 , 则用1个字节表示 , 其二进制为1000 0001 。
  3. 如果字符长度大于1且小于64 , 并且字符全是ascii字符(小等于127) , 则每个字符用一个字节表示 , 最后一个字节的高位置1 , 表示字符串字符的结束 。 【优化点 , 如果是ascii字符 , 编码时不需要使用length +内容的方式 , 或者直接写入内容】
  4. 如果不满足上述条件 , 则需要使用length +内容的方式 。
  1. 用一个变长int写入字符的长度 , 每个字节 , 高两个分别为编码标记(1:utf8) , 是否结束标记(1:否; 0:结束) 2)将内容用utf-8编码的字符串序列中 , utf8 , 用变长字节(1-3)个字节表示一个字符(英文 , 中文) 。 每一个字节 , 使用6为 , 高两位为标志位 。 【16位】 3字节的存储为【4位】+【6位】+【6位】 , 根据第一个字节高4位判断得出需要几个字节来存储一个字符 。
其反序列化的入口为Input#readString , 就是按照上述规则进行解析即可 , 就不深入探讨了 , 有兴趣的话 , 可以自己去指定地方查阅 。
3 , 布尔类型序列化【为什么如此高效?解密kryo各个数据类型的序列化编码机制,强】实现类为DefaultSerializers $ BooleanSerializer , 序列化:使用1个字节存储boolean类型 , 如果为true , 则写入1 , 否则写入0 。