按位运算符究竟如何在Java中工作?

我目前正在尝试在Java中围绕位和位移运算符。虽然它们在简化的玩具示例(基本上是正整数)中对我来说是有意义的,但是一旦涉及负数,我的理解就会崩溃,在其他一些情况下也是如此。我尝试用两个搜索引擎在互联网上搜索,我甚至检查了Java规范。我找不到任何正确描述按位和位移运算符在Java中如何工作的来源。


Java标准库中特别让我感到困惑的一个函数是 。来自 OpenJdk 的源代码如下所示(LGPLv2 具有类路径异常),并在爪哇文档中摘录:java.lang.Integer.toUnsignedLong(int)


/**

 * 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.   

 */

public static long toUnsignedLong(int x) {

    return ((long) x) & 0xffffffffL;

}

根据上面复制的官方文档,“长整型的高位32位为零,低阶32位等于整数参数的位。但是,我不明白这如何从方法体内部的代码中得出。

在阅读该方法时,以下是我对正x的思路:

  1. 当整数转换为 long 时,其符号位/最高有效位为零。因此,长整型符号位/最高有效位为零,低位等于整数的位。

  2. 由于 long 具有所有最低阶 4 字节,并且由于只有这些字节中包含数据,因此此掩码不起作用,并且返回正确的结果。0xffffffff

然而,当在负面的背景下阅读它时,我的理解就崩溃了:x

  1. 当整数为 cst 到 long 时,其符号位/最高有效位为 1。因此,长号的符号位/最有效位是一,低阶位等于整数的位,除了第四个最低有效字节的最有效位是零,当它在整数中为1时。

  2. 由于 long 在最低顺序为 4 个字节中具有所有 1,在最高顺序的 4 个字节中具有零,因此它具有更改长整型上的符号位的唯一效果,并使四个最低有效位中的错误整数保持不变。因此,它从此方法返回错误的答案,其中整数的符号位在移动到长整型时会更改。0xffffffff

但是,当我测试此方法时,我得到的结果与Javadoc一致。我怀疑我误解了Java中按位运算符或其两个补码整数表示的一个或多个基本点,我希望这个问题可以澄清这些要点。


梦里花落0921
浏览 199回答 1
1回答

至尊宝的传说

按位运算符的工作方式完全符合您的预期。它们是严格的位运算符,根本不考虑位的语义。有时,使用断点运行代码最为简单。对于您的具体示例,我将操作的步骤转换为原子语句,并使用 打印结果。Long.toStringint x = -57;// step 1:long xCast = (long) x;System.out.println(Long.toString(xCast, 2)); // -1110011 - this is not the bitwise representation however.long mask = 0xffffffffL;System.out.println(Long.toString(mask, 2)); // 11111111111111111111111111111111// step 2:long result = ((long) x) & mask;System.out.println(Long.toString(result, 2)); // 11111111111111111111111111000111步骤 1 是操作外观的主要原因。在 Java 中,所有(严格数字)值都是有符号的(字符是无符号的)。这意味着,正如您正确指出的那样,所有最高位都是符号位。然而,有趣的部分是,如果一个数字是负数,那么其余位会做什么。以下主题已经涵盖了“二的补码”的基础知识:什么是“2的补码”?这个维基百科页面也是如此:https://en.wikipedia.org/wiki/Two%27s_complement为了缩短它,在java中,对于整数:int zero = 0; // == 0b00000000_00000000_00000000_00000000int maxPositive = Integer.MAX_VALUE; // == 0b01111111_11111111_11111111_11111111int minus1 = -1; // == 0b11111111_11111111_11111111_11111111int minNegative = Integer.MIN_VALUE; // == 0b10000000_00000000_00000000_00000000因此,一切正常的原因是,如果整数为负数,则在强制转换时,整个上部 32 位将转换为 1,否则数字的表示值将发生变化。有效:int x = 0b11111111_11111111_11111111_11000111;转换为:long xCast = 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11000111;由于您作为开发人员希望该方法仅返回初始设置的位,因此您必须从结果中屏蔽上位。这是在步骤 2 中完成的。因此,您的示例的答案:Java中非浮动值的表示是二的补码,因此,当智能地将值从int转换为long时,对于负数,上面的位被1填充。因此,它们必须被删除。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java