Java中的Narrowing Primitive Conversion

前言

在看一个 RPC 框架的序列化部分的代码时,学习了关于Narrowing Primitive Conversion的知识。

正文

今天在看一个 RPC 框架的序列化部分的代码时,发现了这样一段逻辑:

1
2
3
4
5
6
7
8
9
public void writeFixedInt32(int value) {

...

// 将int类型的value转换成包含了4个item的byte[]
for(int i = 0; i < 4; ++i) {
this.buf[pos++] = (byte)(value >> 8 * i);
}
}

这段逻辑是将int类型的 value 转换成包含了4个 item 的byte[],注意这里:

1
(byte)(value >> 8 * i)

在循环体内,每次都进行了这个操作。

第1次是将 value 右移 0 位,然后强转成 byte
第2次是将 value 右移 8 位,然后强转成 byte
第3次是将 value 右移 16 位,然后强转成 byte
第4次是将 value 右移 24 位,然后强转成 byte

为什么要这样移位呢?这段逻辑目的是将一个整型(基本类型int)的数转成 byte[],在 Java 中,int 是 32 位,而 byte 是 8 位;另外,在《Java语言规范》中规定,进行基本类型强制转换时,如果是位数多的类型转换为位数低的类型,那么从低位开始,保留要转换成的类型的位数个位不变,剩下的超过要转换类型的位数的位全部抛弃。一个 int 包含了 4 个 8位,直接做一次强转(byte)value的话,的到的结果只是这个 int 的最低 8 位,如果想要将 int 包含的因此,要想把一个 int 的所有 4 个 8 位值全拿到的话,那么就需要将高位右移到低位上再做强转,这样就能依次把 4 个 8位数全都拿到了。

上面的 “位数多的类型转换为位数低的类型” 这种操作,在《Java语言规范》中专门有个名词描述,叫做 Narrowing Primitive Conversion 原文在这里:

5.1.3 Narrowing Primitive Conversion

22 specific conversions on primitive types are called the narrowing primitive
conversions:

  • short to byte or char
  • char to byte or short
  • int to byte, short, or char
  • long to byte, short, char, or int
  • float to byte, short, char, int, or long
  • double to byte, short, char, int, long, or float

A narrowing primitive conversion may lose information about the overall
magnitude of a numeric value and may also lose precision and range.

A narrowing primitive conversion from double to float is governed by the IEEE
754 rounding rules (§4.2.4). This conversion can lose precision, but also lose range,
resulting in a float zero from a nonzero double and a float infinity from a finite
double. A double NaN is converted to a float NaN and a double infinity is
converted to the same-signed float infinity.

A narrowing conversion of a signed integer to an integral type T simply discards
all but the n lowest order bits, where n is the number of bits used to represent type
T. In addition to a possible loss of information about the magnitude of the numeric
value, this may cause the sign of the resulting value to differ from the sign of the
input value.

…其他内容

参考资料

How are integers cast to bytes in Java?

【转】java中byte, int的转换, byte String转换

Narrowing Primitive Conversion