问题描述
class shift_right {
public static void main(String args[]) {
char hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
byte b = (byte) 0xf1;
System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);
}
}
我无法理解这里发生了什么
System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);
为什么要使用 0xf1 和 0x0f。
解决方法
就像我在评论中所说的那样,您似乎没有清楚地了解位操作的工作原理以及如何使用它们。我的建议是做一些关于按位运算的练习,这样你就知道如何使用它们。不过,我会检查这段代码在做什么?
这段代码在做什么?
此代码将存储在变量 b
中的字节转换为十六进制形式。十六进制数组只允许我们将十进制转换为十六进制形式。这更像是一个中间步骤。
二进制转十进制?
假设我们有字节 1010 1010
。要将其转换为十六进制,我们可以参考二进制转十六进制表
我们知道 1010 1010
是 A A
,可以写成 0xAA
。
此代码如何工作?
从上面的转换我们知道,我们可以直接将4位转换成16进制。代码也在做同样的事情。然而,我们面临的问题是我们如何准确地将一个二进制数一次转换为 4 位十六进制数。
这是按位运算发挥作用的地方。它们使我们能够相对轻松地进行切片、清除、设置、切换等操作。假设我们有一个十六进制 1000 1010
我们要转换
1010
-> A
1000
-> 8
按位 AND 可以让我们清除特定位置的位。如果您与 1 位 AND ,则它保持不变。但是,如果您将其与 0 相加。这些位将被清除。
第 1 步:转换 1010
1000 1010
0000 1111 (0x0F)
---------
0000 1010 <- the MSB 4 bits are now cleared. This will allow us to convert the 1010 to hex easily
1010
是十进制的 10
,数组中的第十个元素是“A”。所以 hex[10]
给出 A。
第 2 步:转换 1000
如果我们只是用 0xF0
做一些明智的 AND 操作。我们得到的值是 1000 0000
,它是 -127
,而不是 8
。我们需要以某种方式将其写入 0000 1000
,即 8
。这就是向右移动的用武之地。
1000 1010 >> 4
---------
1111 1000 <- result of shifting 4 times
现在,您可能想知道到底发生了什么。为什么不是移动4次0000 1000
的结果?
当位右移时,有符号位被扩展并取代被移位的位。这称为 Arithmetic Shift,它发生在有符号字节上,而不是 Logical Shift 发生在无符号字节上。如果前导位为 0,则算术移位与逻辑移位非常相似。因此,现在要清除导致符号扩展的所有位,我们需要将数字与 0x0F 进行 AND 运算
1111 1000
0000 1111 (0x0F)
---------
0000 1000 This is 8 in decimal and hex[8] gives us '8'
所以最后我们得到 "0x" + "8" + "A"
,即 "0x8A"