震惊!Integer的背后竟然是这个样子!!!

1. 疑问

最近在刷Leetcode的时候,遇到这样一个题:

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围[-2^{31},2^{31}]。请根据这个假设,如果反转后整数溢出那么就返回 0。

读完题后问了自己几个问题,发现自己都不清楚:

  1. 32位整数是多少?32位是指什么?
  2. 32为有符号整数的范围为什么是[-2^{31},2^{31}]?
  3. 二进制怎么表示?

掏出计算器用二进制算了一下,2^{32}=4294967295,2^{31}=2147483647

到这里,上面的问题基本上搞明白了,新的问题来了:

  1. 二进制怎么表示正负数
  2. 二进制的正负数怎么计算,计算机是怎么处理的
  3. 什么是原码?反码?补码?
  4. Java中是如何处理Integer的?

2. 开始入正题

2.1. 二进制、原码、反码、补码

为什么要有补码?

这里以4位bit为例,二进制最高位0代表+1代表-

整数 原码
4 0 100
-4 1 100
0 0000
5 0 101
-5 1 101
2 0010
7 0 111
-7 1 111
5 0110

因为计算机中没有减法,我们发现,这些数的正负数之和,只有4的二进制计算是正确的,结果为0。为了解决这个问题,所以就有了反码、补码的概念。

整数 原码 反码 补码
4 0 100 0 100 0 100
-4 1 100 1 011 1 100
0 - - 0000
5 0 101 0 101 0 101
-5 1 101 1 010 1 011
0 - - 0000
7 0 111 0 111 0 111
-7 1 111 1 000 1 001
0 - - 0000

通过补码进行正负数的计算,结果就对了

2.1.1. 原码

最高位表示正负号,0代表整数,1代表负数,其它位表示数值的二进制

2.1.2. 反码

  • 正数的反码:与原码一致
  • 负数的反码:最高位符号位不变,其它位取反

2.1.3. 补码

  • 正数的补码:与原码一致
  • 负数的补码:反码 + 1

2.2. Java中的Integer

    @Test
    void testLocal() {
        Integer maxInt = Integer.MAX_VALUE;
        Integer minInt = Integer.MIN_VALUE;

        log.info("十进制:min = {}, max = {}", minInt, maxInt);
        String minBinary = Integer.toBinaryString(minInt);
        String maxBinary = Integer.toBinaryString(maxInt);
        log.info("二进制:minBinary {}位 = {}, maxBinary {}位 = {}", minBinary.length(), minBinary, maxBinary.length(), maxBinary);
        log.info("int 0 = binary {}", Integer.toBinaryString(0));

        log.info("{} = {}, {} = {}", minInt + 1, Integer.toBinaryString(minInt + 1), maxInt - 1, Integer.toBinaryString(maxInt - 1));
        log.info("越界intMax + 1 = {}", maxInt + 1);
    }
复制代码

Java中的Integer的大小是32位bit,最小值和最大值范围就是[-2^{31},2^{31}],数值大小是31位,最高位0/1表示正负。

从二进制的角度来看,对正整数的最大值是31位1,加1后所有位进1变为0,最后结果就是最高位由0 -> 1,得到的二进制结果和负数的最小值相同,这样就容易理解java中的整数越界,以及Integer的范围。

3. 总结

  1. 计算机中的计算只有加法和二进制,为了原码、反码、补码就是为了解决计算机中的运算
  2. 整数越界,就是在固定32位长度下,对二进制计算结果转为整数的过程
  3. 通过一个问题引申出一系列的问题,从数值范围 -> 二进制表示 -> 有/无符号 -> 二进制计算 -> 原码/反码/补码 -> 整数越界...

4. 最后

了解的二进制后,Java中的移位运算符("<<"、">>"、">>>")是怎么做运算的?

猜你喜欢

转载自juejin.im/post/5ef468eef265da22da54a27b
今日推荐