写点什么

Opentelemetry 字节数组转十六进制字符串源码解析

作者:喝水不抬头

在分布式追踪系统中,通常需要讲二进制格式的 Trace ID 转换为可读的字符串格式,比如 TraceId 类提供的这个方法,里边的位运算设计的非常巧妙。

public static String fromBytes(byte[] traceIdBytes)
复制代码

traceIdBytes 对应一个 16 字节,也就是 128 个二进制位,每一个字节的高 4 位和低 4 位分别转换成十六进制字符,最终会转换为长度为 32 的字符串。

有符号的 byte 转换为无符号的整数

public static void byteToBase16(byte value, char[] dest, int destOffset) {        int b = value & 255;        dest[destOffset] = ENCODING[b];        dest[destOffset + 1] = ENCODING[b | 256];}
复制代码


在 Java 中,byte 类型是有符号的,范围是-128 到 127,而我们在处理十六进制转换时,需要的是无符号类型,比如:

byte b = (byte) 0xab;  // 0xAB = 十进制171,但作为byte会溢出System.out.println(b);  // 输出: -85 (不是我们期望的171)
复制代码

value & 255 的作用就是将 byte 值转换为无符号的整数(范围 0-255)

value (byte 0xab, 提升为int): 11111111 11111111 11111111 10101011255 (int):                   00000000 00000000 00000000 11111111按位与(&)结果:                 00000000 00000000 00000000 10101011
复制代码

从 ENCODING 数组直接获取十六进制字符

在获取每一个无符号整数高 4 位和低 4 位对应的十六进制字符时,并没有每次都会去计算,而是通过已经计算好的数组来实现的。

171对应的二进制:10101011ENCODING[171]=171的高4位对应的字符,也即是1010对应的字符,结果为aENCODING[171|256]=ENCODING[171 + 256] = 171的低4位对应的字符,也即是1011对应的字符,结果为b
复制代码

我们来看一下 ENCODING 数组是如何提前做好计算的

private static char[] buildEncodingArray() {        char[] encoding = new char[512];
for(int i = 0; i < 256; ++i) { encoding[i] = "0123456789abcdef".charAt(i >>> 4); encoding[i | 256] = "0123456789abcdef".charAt(i & 15); }
return encoding; }
复制代码

ENCODING 数组的容量是 512,数组下标 0-255 存放数组下标这个整数高 4 位对应的字符,而低 4 位对应的字符,则放在下标+256 的位置。比如下标 171,ENCODING[171]存放 171 这个整数高 4 位对应的字符,而 171 的低 4 位对应的字符,则放在下标 171+256=427 的位置。


i >>> 4将整数无符号右移动4位,获取高4位encoding[i] = "0123456789abcdef".charAt(i >>> 4);i & 15获取低4位,最后将结果放在i+256索引处encoding[i | 256] = "0123456789abcdef".charAt(i & 15);
复制代码

由于 4 位二进制位对应的整数范围位 0-15,因此通过长度为 16 的字符串"0123456789abcdef"的 charAt 方法直接获取即可。

实例


16位byte如下[95, 86, -81, -52, 116, -57, 65, -94, 108, 1, -78, 84, 50, -46, -14, -59]
展开前三个对应的8位二进制位[01011111, 01010110, 10101111, -52, 116, -57, 65, -94, 108, 1, -78, 84, 50, -46, -14, -59]
01011111高4位对应'5',低4位对应'f'01010110高4位对应'5',低4位对应'6'10101111高4位对应'a',低4位对应'f'
转换后的结果如下5f56afcc74c741a26c01b25432d2f2c5
复制代码


发布于: 刚刚阅读数: 5
用户头像

还未添加个人签名 2018-05-15 加入

还未添加个人简介

评论

发布
暂无评论
Opentelemetry字节数组转十六进制字符串源码解析_喝水不抬头_InfoQ写作社区