场景描述:
Java 中基本类型都是有符号数值,如果接收到了 C/C++ 处理的无符号数值字节流,将出现转码错误。
解决方式:
使用 long 型的 64 位十六进制数 0xFFFFFFFFL,对取得的 32 位(4字节)的整型数值,做按位与(&)操作,
并以 long 型保存这个无符号数值,如下:
long vUnsigned = bf.getInt() & 0xFFFFFFFFL;
注:0xFFFFFFFFL 的高32位默认补0,末尾的 L 代表 long 型。
注:事实上,Java的 Integer 中已经实现此方法:
/**
* Converts the argument to a {@code long} by an unsigned
* conversion. In an unsigned conversion to a {@code long}, the
* high-order 32 bits of the {@code long} are zero and the
* low-order 32 bits are equal to the bits of the integer
* argument.
*
* Consequently, zero and positive {@code int} values are mapped
* to a numerically equal {@code long} value and negative {@code
* int} values are mapped to a {@code long} value equal to the
* input plus 232.
*
* @param x the value to convert to an unsigned {@code long}
* @return the argument converted to {@code long} by an unsigned
* conversion
* @since 1.8
*/
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
package sparkstreaming_action.socket.main;
import java.nio.ByteBuffer;
public class UnsignedIntTest {
public static void main(String[] args) {
/** 使用 ByteBuffer 存放 64 位无符号整数的字节码
* 1. 默认实例化 HeapByteBuffer
* 2. 以 Byte[] 形式存放数据
* 3. Byte 取值范围:-128 ~ 127
* 4. 字节数组的低位索引号 对应 二进制的高位
*/
ByteBuffer bf = ByteBuffer.allocate(64);
/**
* 如下二进制(无符号 32 位整数值):
* 10000000 00000100 00000010 00000001
* 代表无符号十进制整数:
* 2147746305
* 代表有符号十进制整数:
* -2147220991
*
* 将此十进制数按字节存入字节数组缓存中
* 1. 前 32 位置 0
* 2. 后 32 位存放数值
*/
bf.put(0, Byte.valueOf("0")); // 00000000
bf.put(1, Byte.valueOf("0")); // 00000000
bf.put(2, Byte.valueOf("0")); // 00000000
bf.put(3, Byte.valueOf("0")); // 00000000
bf.put(4, Byte.valueOf("-128")); // 10000000
bf.put(5, Byte.valueOf("4")); // 00000100
bf.put(6, Byte.valueOf("2")); // 00000010
bf.put(7, Byte.valueOf("1")); // 00000001
/** 1. 以 Long 型读取8字节整数
* 此时读取正确,为32位的无符号整数
*/
System.out.println("--------------------read 8 bytes, unsigned value------------------------");
long vLong = bf.getLong(0); // 从 index 0 开始读
System.out.println(vLong);
System.out.println(Long.toBinaryString(vLong));
System.out.println(Long.toBinaryString(2147746305L));
/** 2. 以 Int 型读取4字节(低位)整数
* 此时将带有符号位,读取位32位有符号整数,不是预期读到的数据
*
* *那么,如何只读4字节就能读到32位无符号整数呢?
*/
System.out.println("--------------------read lower 4 bytes, signed value---------------------");
int vInt = bf.getInt(4); // 从 index 4 开始读
System.out.println(vInt);
System.out.println(Integer.toBinaryString(vInt));
System.out.println(Integer.toBinaryString(-2147220991));
/** 3. 只读4字节,并且读到32位无符号整数
* 使用 & 操作符,转成Long型,并取低32位
*/
System.out.println("--------------------read lower 4 bytes, unsigned value---------------------");
用 Int 型 0xFFFFFFFF 按位与,并不能行的通,如果不涉及符号位则可用
//long vUnsigned = bf.getInt(4) & 0xFFFFFFFF;
// 使用 Long 型 0xFFFFFFFFL,按位与,与下面的代码效果相同
//long vUnsigned = bf.getInt(4) & (long)(Math.pow(2, 32) - 1);
long vUnsigned = bf.getInt(4) & 0xFFFFFFFFL;
System.out.println(vUnsigned);
System.out.println(Long.toBinaryString(vUnsigned));
System.out.println(Long.toBinaryString(2147746305L));
System.out.println("--------------------0xFFFFFFFF and 0xFFFFFFFFL---------------------");
System.out.println("0xFFFFFFFF is 32 bits Int value: " + 0xFFFFFFFF); // -1
System.out.println("0x0FFFFFFFF is 32 bits Int value: " + 0x0FFFFFFFF); // -1
System.out.println("0xFFFFFFFFL is 64 bits Long value: " + 0xFFFFFFFFL); // 4294967295
}
}
--------------------read 8 bytes, unsigned value------------------------
2147746305
10000000000001000000001000000001
10000000000001000000001000000001
--------------------read lower 4 bytes, signed value---------------------
-2147220991
10000000000001000000001000000001
10000000000001000000001000000001
--------------------read lower 4 bytes, unsigned value---------------------
2147746305
10000000000001000000001000000001
10000000000001000000001000000001
--------------------0xFFFFFFFF and 0xFFFFFFFFL---------------------
0xFFFFFFFF is 32 bits Int value: -1
0x0FFFFFFFF is 32 bits Int value: -1
0xFFFFFFFFL is 64 bits Long value: 4294967295