示例代码:
int a = 255;
byte b = (byte) a;
int c = b & 0xff; // Here be dragons
System.out.println(a);
System.out.println(b);
System.out.println(c);
因此我们从255的整数值开始,将其转换为一个字节(变为-1),然后使用魔术公式将其转换回int。预期的输出是:
255
-1
255
我想知道这个a & 0xff
是否是进行此转化的最佳方式。例如,checkstyle抱怨在这个地方使用幻数,并且忽略此检查的值不是一个好主意,因为在其他地方255可能真的是一个应该避免的幻数。而且我自己为这样的东西定义常量非常烦人。所以我想知道JRE中是否有一种标准方法来代替这种转换?或者可能是已定义的具有最高无符号字节值的常量(类似于Byte.MAX_VALUE,这是最高的有符号值)
所以要保持简短:如何在不使用幻数的情况下将字节转换为int?
好的,到目前为止,提到了以下可能性:
& 0xff
并忽略checkstyle中的幻数255。缺点:其他可能在某些其他范围(不是位操作)中使用此数字的地方也不会被检查。优点:简短易读。& SomeConsts.MAX_UNSIGNED_BYTE_VALUE
之类的代码。缺点:如果我需要在不同的类中,那么我必须为这个darn常量定义我自己的常量类。优势:这里没有神奇的数字。b & ((1 << Byte.SIZE) - 1)
这样聪明的数学运算。编译器输出很可能是相同的,因为它被优化为常量值。缺点:代码相当多,难以阅读。优点:只要1
未被定义为幻数(checkstyle默认忽略它),我们这里没有幻数,我们不需要定义自定义常量。当字节有一天被重新定义为16位(开玩笑)时它仍然有效,因为Byte.SIZE将是16而不是8。还有更多想法吗?也许其他一些聪明的逐位操作比上面的操作短,只使用0和1之类的数字?
答案 0 :(得分:18)
是进行转换的标准方式。如果你想摆脱checkstyle投诉,尝试定义一个常量,它可能会有所帮助:
public final static int MASK = 0xff;
BTW - 请记住,它仍然是自定义转换。 byte
是一种已签名的数据类型,因此byte
永远不会保留值255
。一个字节可以存储位模式1111 1111
,但这表示整数值-1
。
所以实际上你正在进行位操作 - 位操作总是需要一些幻数。
BTW-2:是的,有一个Byte.MAX_VALUE
常数,但这是 - 因为byte
已签名 - 定义为2 7 -1(= 127)。所以它对你的情况没有帮助。 -1需要一个字节常量。
答案 1 :(得分:10)
忽略checkstyle。 0xFF
不是一个幻数。如果为它定义一个常量,则常量 是一个魔术常量,这比0xFF
本身更难理解。在最近几个世纪受过教育的每个程序员都应该更熟悉0xFF
而不是他的女朋友,如果有的话。
我们应该写这样的代码吗?
for(int i = Math.ZERO; ... )
答案 2 :(得分:4)
答案 3 :(得分:2)
我为此写了一个方法
public static int unsigned(byte x) {
return int (x & 0xFF);
}
也为short和int参数重载(其中int扩展为long)。
而不是0xFF你可以使用Byte.MAX_VALUE + Byte.MAX_VALUE + 1来保持FindBug关闭,但我认为它是一个混淆。并且很容易弄错(先前的版本)。
答案 4 :(得分:1)
Java 8提供Byte.toUnsignedInt
和Byte.toUnsignedLong
(可能是非常大的字节)方法:
byte b = (byte)255;
int c = Byte.toUnsignedInt(b); // 255
long asLong = Byte.toUnsignedLong(b); // 255