Kotlin中如何将有符号Long转为ByteArray并保持排序顺序?
Kotlin实现Long转保持字典序的ByteArray
需求说明
需要将Kotlin中的有符号Long类型转换为ByteArray,要求生成的字节数组的字典序与原Long值的数值顺序完全一致,且每个Long对应固定的8字节数组。
已尝试ByteBuffer#putLong、DataOutputStream#writeLong及手动小端编码等方案,但均无法满足顺序保持的要求。
参考测试用例
class LongToByteArrayTest { @Test fun canConvertLongToByteArrayPreservingOrder(){ // 测试用的Long值集合 val longs = mutableListOf( Long.MIN_VALUE, Long.MAX_VALUE, 0, -1, +1, -2, +2, -10, +10, -42, +42, Long.MAX_VALUE / 2, Long.MIN_VALUE / 2 ) longs.sort() for ((lower, upper) in longs.windowed(size = 2)) { println("Lower: ${lower}, Upper: ${upper}") assert(lower < upper) { "Fail: long values are out of order!" } val lowerBytes = toStableBytes(lower) val upperBytes = toStableBytes(upper) assert(compareBytesLex(lowerBytes, upperBytes) < 0){ "Fail: byte arrays are out of order!" } } } fun compareBytesLex(byteArray1: ByteArray, byteArray2: ByteArray): Int { val min = min(byteArray1.size, byteArray2.size) for (i in 0 until min) { val myByteUnsigned = byteArray1[i].toInt() and 0xff val otherByteUnsigned = byteArray2[i].toInt() and 0xff val cmp = myByteUnsigned - otherByteUnsigned if (cmp != 0) { return cmp } } return byteArray1.size - byteArray2.size } fun toStableBytes(value: Long) : ByteArray { TODO("how do we do this?") } }
解决方案:实现toStableBytes方法
核心思路是调整有符号Long的符号位,将其转换为无符号语义的数值后,再按大端序(高位在前)编码为字节数组。这样处理后,字节数组的字典序会和原Long的数值顺序完全匹配。
具体实现代码:
fun toStableBytes(value: Long): ByteArray { // 转换为"无符号化"的Long:翻转符号位,让负数编码整体小于正数 val adjusted = value xor Long.MIN_VALUE return ByteArray(8).apply { // 按大端序写入调整后的值 this[0] = (adjusted shr 56).toByte() this[1] = (adjusted shr 48).toByte() this[2] = (adjusted shr 40).toByte() this[3] = (adjusted shr 32).toByte() this[4] = (adjusted shr 24).toByte() this[5] = (adjusted shr 16).toByte() this[6] = (adjusted shr 8).toByte() this[7] = adjusted.toByte() } }
原理说明
- 符号位调整:
Long.MIN_VALUE的二进制是最高位为1、其余位为0。通过xor操作翻转原Long的最高符号位:- 原负数(符号位1)调整后最高位变为0,对应无符号语义下的较小值
- 原正数(符号位0)调整后最高位变为1,对应无符号语义下的较大值
调整后的数值无符号顺序,与原Long的有符号数值顺序完全一致。
- 大端序编码:按高位到低位的顺序写入字节数组,确保字典序比较时高位字节优先级更高,和数值大小比较逻辑对齐。
验证
将上述实现替换测试用例中的TODO代码后,所有测试用例均可通过,满足字节数组字典序与原Long数值顺序一致的要求。
内容的提问来源于stack exchange,提问作者Martin Häusler
相关产品推荐
相关产品推荐

