Java左移操作相关问题咨询:异常现象解析及丢失信息去向
嘿,这个左移的坑我刚学Java位操作时也踩过,当时盯着输出愣了半天~咱们来逐个拆解这些现象背后的门道:
1. 为什么-1左移31位得到-2147483648?
先看你的测试代码和输出:
int x = -1 << 31; System.out.print(Integer.toBinaryString(-1) + " -1\n"); System.out.print(Integer.toBinaryString(x) + " " + x + "\n"); // 输出: // 11111111111111111111111111111111 -1 // 10000000000000000000000000000000 -2147483648
Java里的int是32位有符号整数,用补码存储。-1的补码是32个连续的1。左移31位时,所有位向左挪31位,右边补31个0,最左边的31个1都被“挤出去”(溢出丢弃),只剩原本最右边的1移到了最高位(符号位),最终二进制就是10000000...0000——这正好是32位int能表示的最小值-2^31(也就是-2147483648),完全符合预期。
2. 为什么-1左移32位还是-1?
这是最容易懵的点,看代码:
int x = -1 << 32; System.out.print(Integer.toBinaryString(-1) + " -1\n"); System.out.print(Integer.toBinaryString(x) + " " + x + "\n"); // 输出: // 11111111111111111111111111111111 -1 // 11111111111111111111111111111111 -1
这可不是Java的bug,是语言规范明确规定的行为!对于int类型的移位操作,移位的位数会先做模32运算(取余数)。说白了,你写a << n时,如果n≥32,实际生效的位数是n % 32。所以-1 << 32等价于-1 << 0——左移0位,结果当然还是原数-1。同理,要是你左移33位,就等价于左移1位,结果会是-2。
3. 为什么-2147483648左移1位得到0?
看这段测试:
System.out.println(-2147483648 << 1); // 输出0
-2147483648是int的最小值,它的补码是10000000000000000000000000000000(最高位1,其余全0)。左移1位时,最高位的1直接被溢出丢弃,右边补0,所有位变成全0,对应的十进制就是0,这完全符合左移的规则:溢出的高位直接丢,不留任何痕迹。
关于“左移丢失的信息是否被存储”的问题
答案很明确:不会被存储。Java的所有位操作(左移、右移、无符号右移)中,被移出的比特位都是直接丢弃的,没有任何内置机制会保存这些“丢失”的信息。如果你的业务需要保留溢出的内容,得自己手动处理——比如用更大的类型(比如long)来承接移位结果,这样溢出的位就会存在long的高位里。
内容的提问来源于stack exchange,提问作者OneFlowerOneWorld

