为什么当 b 是一个字节且在 Java 中值为 -1 时,b >>> 1 总是等于 -1?

问题描述 投票:0回答:1

我知道

>>>
是无符号右移,并且由于Java中的
byte
是有符号的8位,所以-1将表示为
1111 1111
。结果,对于下面的代码:

byte b = (byte) -1;
b >>>= 1;
System.out.println(b);

它不应该打印

127
(二进制为0111 1111)吗?但无论我执行
-1
>>>
多少次(例如循环),我得到的结果始终是
b

任何人都可以解释为什么以及以什么方式我可以获得我期望的结果(即执行无符号右移,其中

-1
右移一次等于Java中
127
byte
)?我的理解有错吗?非常感谢!

java binary byte bitwise-operators bit-shift
1个回答
0
投票

您遇到了一系列非常奇怪的 Java 设计选择,这使得这段代码变得很糟糕。让我们来分解一下:

鲜为人知的java方面1:
byte
short
char
boolean
较差

在java中,

byte
short
char
boolean
inferior原语,
int
long
double
float
superior基元。除了数组存储和数组加载之外,没有其他操作码。 java中没有将2个字节加在一起的操作码。它只是不存在。。鉴于
javac
不知道要生成什么,这实际上是不可能的。所以,相反:

byte b = 5;
byte c = 10;
byte d = b + c;

实际上意味着:

byte b = 5;
byte c = 10;
byte d = (int) b + (int) c;

因此,这是一个编译器错误 -

int + int
的结果是
int
,并且如果没有显式转换,则不允许尝试将
int
分配给
byte

您可以轻松查看任何java字节码列表。您会找到 FADD、DADD、IADD 和 LADD。但你找不到 BADD、CADD 或 SADD。

鲜为人知的 Java 方面 2:复合赋值运算符自动转换。

这个:

a += b;
实际上与
a = a + b;
根本不一样!我知道你是这么教的,但这是不正确的。事实上,它等于
a = (byte) (a + b);
,其中
byte
是 a 的类型。见证人:

double d = 5.5;
int x = 5;
x = x + d; // obviously, compiler error. Explicit cast needed.

对:

double d = 5.5;
int x = 5;
x += d;

完全合法。结果 x 为 10。完整流程为:

  • x 是 5。这会转换为
    double
    ,因为 java 只能在两个相同类型的事物之间进行数学计算。
  • d
    是5.5,已经是双倍了,不错。
  • DADD
    字节码被执行;结果是 10.5.
  • 将其转换为
    int
    ,生成
    10
    ,并将其分配给
    x

如果你想看到这个,请运行

javap

两者结合

因此,让我们分解您的代码:

byte b = (byte) -1;

这使得 int -1(32 个“1”位),然后将其转换为字节,导致

b
具有值
1111 1111
。到目前为止,一切都很好,没有什么令人惊讶的。

b >>>= 1;

呼男孩。这看起来很简单,但是却非常复杂。它的语法糖是:

b = (byte) (((int) b) >>> 1);

要打破那个

  • (int) b
    结果为 32 个 1 位。
    b
    的字节数为 -1,将其转换为 int 会产生 -1 int,即 32 个 1 位。
  • >>> 1
    然后将其设为 0,后跟 31 个 1 位。
  • 然后将其转换回一个字节,即 -1 - 8 1 位。

那么我该怎么做呢?

基本上不要使用

byte
。除非在以下情况下,否则不要使用劣质基元:

  • 本质上,您在签名(即方法的返回类型或参数类型)中使用它们作为 API 文档。
  • 你创建了一个数组。
    byte[]
    很有用,而且每个项目确实只占用 1 个字节。

对于所有其他事情(例如单个字段和针对数学的局部变量,例如您正在做的事情),不要。正如您在这里发现的那样,他们的行为并不像您想象的那样。

只需使用整数即可。如果您想要一个“无符号字节”,只需创建一个

int
变量并使用它:

byte b = (byte) -1;
int x = b & 0xFF; // x is now 0000...0000 1111 1111.
System.out.println(x); // prints 255
x >>= 1;
System.out.println(x); // prints 127

byte
作为单个值(不是
byte[]
- 只是
byte
在 64 位架构上,在任何方面都不会比 int
 甚至可能比 
long
 更高效。 Java 不会分配更少的内存(因为所有东西都必须在字边界上对齐),操作速度并不会更快(CPU 已经在 64 位块中工作)。

© www.soinside.com 2019 - 2024. All rights reserved.