【问题标题】:How are integers internally represented at a bit level in Java?在 Java 中,整数如何在内部以位级别表示?
【发布时间】:2026-01-07 19:10:02
【问题描述】:

我试图了解 Java 如何在内部存储整数。我知道所有java原始整数都是有符号的(除了short?)。这意味着该数字在一个字节中可用的位数减少了。

我的问题是,所有整数(正数和负数)都存储为二进制补码还是仅是二进制补码中的负数?

我看到规格上写着x bit two's complement number。但我经常感到困惑。

例如:

  int x = 15; // Stored as binary as is?  00000000 00000000 00000000 00001111?
  int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010

编辑

要清楚,x = 15

   In binary as is: `00000000 00000000 00000000 00001111'
  Two's complement: `11111111 11111111 11111111 11110001`

因此,如果您的答案是all,则将数字存储为二进制补码:

  int x = 15; // 11111111 11111111 11111111 11110001
  int y = -22 // 11111111 11111111 11111111 11101010

这里的混乱再次是标志说,两者都是负数。可能是我误读/误解了吗?

编辑 不确定我的问题是否令人困惑。强制隔离问题:

我的问题正是:正数是否存储在binary as is,而负数是否存储为two's complement

有人说所有都存储在二进制补码中,一个答案说只有负数存储为二进制补码。

【问题讨论】:

    标签: java memory binary store twos-complement


    【解决方案1】:

    让我们从总结 Java 原始数据类型开始:

    字节:字节数据类型是一个 8 位有符号二进制补码整数

    Short:Short 数据类型是一个 16 位有符号二进制补码整数

    int: Int 数据类型是 32 位有符号二进制补码整数

    long:Long 数据类型是 64 位有符号二进制补码整数

    float: Float 数据类型是单精度 32 位 IEEE 754 浮点

    double:double 数据类型是双精度64 位IEEE 754 浮点

    boolean:布尔数据类型代表一位信息

    char: char 数据类型是单个 16 位 Unicode 字符

    Source

    补码

    “很好的例子来自wiki,通过注意到 256 = 255 + 1 来实现与二进制补码的关系,并且 (255 - x) 是 x 的补码

    0000 0111=7 二进制补码是 1111 1001= -7

    它的工作方式是 MSB(最高有效位)接收负值,因此在上述情况下

    -7 = 1001= -8 + 0+ 0+ 1

    正整数通常存储为简单的二进制数(1 是 1,10 是 2,11 是 3,依此类推)。

    负整数存储为其绝对值的二进制补码。当使用这种表示法时,正数的二进制补码是负数。

    Source

    由于这个答案我得到了一些分数,我决定向它添加更多信息。

    更详细的答案:

    其中有四种主要的方法可以用二进制表示正数和负数,即:

    1. 有符号幅度
    2. 补码
    3. 二的补码
    4. 偏见

    1.签名幅度

    用最高位表示符号,其余位表示绝对值。其中0代表正数1代表负数,例如:

    1011 = -3
    0011 = +3
    

    这种表示更简单。但是,您不能像添加十进制数一样添加二进制数,这使得在硬件级别上实现起来更加困难。此外,这种方法使用两种二进制模式来表示 0,-0 (1000)+0 (0000)

    2。补码

    在这种表示中,我们反转给定数字的所有位以找出它的互补。例如:

    010 = 2, so -2 = 101 (inverting all bits).
    

    这种表示的问题是仍然存在两个位模式来表示 0,negative 0 (1111)positive 0 (0000)

    3.二进制补码

    为了找到一个数字的负数,在这个表示中,我们将所有位反转,然后添加一位。添加一位解决了两个位模式表示 0 的问题。在这个表示中,我们只有一个模式 0 (0000)

    例如,我们想使用 4 位找到 4(十进制)的二进制负表示。首先,我们将 4 转换为二进制:

    4 = 0100
    

    然后我们反转所有位

    0100 -> 1011
    

    最后,我们加一点

    1011 + 1 = 1100.
    

    如果我们使用 4 位二进制补码表示,那么 1100 相当于十进制的 -4。

    找到互补的更快方法是将第一位固定为值 1 并将其余位取反。在上面的例子中,它会是这样的:

    0100 -> 1100
    ^^ 
    ||-(fixing this value)
    |--(inverting this one)
    

    Two's Complement 表示,除了只有一种表示 0 外,它还以与十进制相同的方式将两个二进制值相加,不同符号的偶数。尽管如此,还是有必要检查溢出情况。

    4.偏见

    此表示用于表示 IEEE 754 规范中浮点的指数。它的优点是所有位为零的二进制值代表最小值。所有位为 1 的二进制值代表最大值。顾名思义,该值以二进制编码(正或负),n 位带有偏差(通常为 2^(n-1) 或 2^(n-1)-1)。

    所以如果我们使用 8 位,十进制的值 1 用二进制表示,使用 2^(n-1) 的偏差,由值:

    +1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
    converting to binary
    1000 0001
    

    【讨论】:

      【解决方案2】:

      Java 整数是 32 位的,并且总是有符号的。这意味着,最高有效位 (MSB) 用作符号位。 int 表示的整数只不过是位的加权和。权重分配如下:

      Bit#    Weight
      31      -2^31
      30       2^30
      29       2^29
      ...      ...
      2        2^2
      1        2^1
      0        2^0
      

      注意MSB的权重是负数(实际上是最大可能的负数),所以当这个位打开时,整数(加权和)变为负数。

      让我们用 4 位数字来模拟它:

      Binary    Weighted sum            Integer value
      0000       0 + 0 + 0 + 0           0
      0001       0 + 0 + 0 + 2^0         1
      0010       0 + 0 + 2^1 + 0         2
      0011       0 + 0 + 2^1 + 2^0       3
      0100       0 + 2^2 + 0 + 0         4
      0101       0 + 2^2 + 0 + 2^0       5
      0110       0 + 2^2 + 2^1 + 0       6
      0111       0 + 2^2 + 2^1 + 2^0     7 -> the most positive value
      1000      -2^3 + 0 + 0 + 0        -8 -> the most negative value
      1001      -2^3 + 0 + 0 + 2^0      -7
      1010      -2^3 + 0 + 2^1 + 0      -6
      1011      -2^3 + 0 + 2^1 + 2^0    -5
      1100      -2^3 + 2^2 + 0 + 0      -4
      1101      -2^3 + 2^2 + 0 + 2^0    -3
      1110      -2^3 + 2^2 + 2^1 + 0    -2
      1111      -2^3 + 2^2 + 2^1 + 2^0  -1
      

      因此,二进制补码并不是表示负整数的唯一方案,而是我们可以说整数的二进制表示总是相同的,我们只是否定最高有效位的权重。而那个位决定了整数的符号。

      在C语言中有一个关键字unsigned(java中没有),可以用来声明unsigned int x;。在无符号整数中,MSB 的权重是正数 (2^31) 而不是负数。在这种情况下,unsigned int 的范围是02^32 - 1,而int 的范围是-2^312^31 - 1

      从另一个角度来看,如果您将x 的二进制补码视为~x + 1(不是 x 加一),以下是解释:

      对于任何x~x 只是x 的按位倒数,所以无论x 有一个1 位,~x 都会有一个0 位(反之亦然)反之亦然)。所以,如果你把它们加起来,加法中不会有进位,总和只是一个整数,其中每一位都是1

      对于 32 位整数:

      x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111
      x + ~x + 1 =   1111 1111 1111 1111 1111 1111 1111 1111 + 1
                 = 1 0000 0000 0000 0000 0000 0000 0000 0000
      

      最左边的1-bit 将被简单地丢弃,因为它不适合 32 位(整数溢出)。所以,

      x + ~x + 1 = 0
      -x = ~x + 1
      

      所以你可以看到否定的x可以用~x + 1来表示,我们称之为x的二进制补码。

      【讨论】:

      • 我的问题很准确:+ve 数字是否存储在binary as is 而-ve 数字是否存储在two's complement
      • 嗯,是的。负数在计算机上表示为其正值的二进制补码。
      • @0605002:如果有的话,您能否提供此答案的参考?虽然我知道这些概念,但从未真正以那种方式思考过它们。最简单、仍然准确的答案。
      • 大学四年,一直不懂2s补码。这个答案教会了我更多。如此简单的事情在世界各地以如此神秘的方式被教授,真是令人难过。
      • 您在这里使用的方案已经是 2 的补码。不是吗?
      【解决方案3】:

      我跑了下面的程序就知道了

      public class Negative {
          public static void main(String[] args) {
              int i =10;
              int j = -10;
      
              System.out.println(Integer.toBinaryString(i));
              System.out.println(Integer.toBinaryString(j));
          }
      }
      

      输出是

      1010
      11111111111111111111111111110110
      

      从输出看来,它一直在使用二进制补码。

      【讨论】:

      • 10 的补码是11111111 11111111 11111111 11110110。你的打印,而 10 的二进制是 1010。所以只有 -ve 数字被存储为二进制补码?
      • 查看 wiki 文章 en.wikipedia.org/wiki/...您为 15 提供的 2 的补数是错误的
      • 如果 msb 位以 1 开头,则为负数
      • 是的 10 的补码是 11111111 11111111 11111111 11110110 是 -10
      • +ve 数字将存储为二进制,符号位在 2 的补码中
      【解决方案4】:

      Oracle 提供了一些关于 Java Datatypes 的文档,您可能会感兴趣。具体来说:

      int:int 数据类型是一个 32 位有符号二进制补码整数。它的最小值为 -2,147,483,648,最大值为 2,147,483,647(含)。

      顺便说一句,short 也存储为二进制补码。

      【讨论】:

        【解决方案5】:

        正数按原样存储/检索。

        e.g) For +ve number 10; byte representation will be like 0-000 0010 
                                                       (0 - MSB will represent that it is +ve).
        So while retrieving based on MSB; it says it is +ve, 
        so the value will be taken as it is. 
        

        但负数将存储在 2 的补码之后(除了 MSB 位),MSB 位将被设置为 1。

        例如)当存储 -10 然后

          0-000 0010  -> (1's complement) -> 0-111 1101 
                      -> (2's complement) 0-111 1101 + 1 -> 0-111 1110
          Now MSB will be set to one, since it is negative no -> 1-111 1110
        

        检索时发现MSB设置为1,所以为负数。 2 的补码将在 MSB 之外进行。

          1-111 1110  --> 1-000 0001 + 1 --> 1-000 0010
          Since MSB representing this is negative 10 --> hence  -10 will be retrived.
        

        选角

        另请注意,当您将 int/short 转换为字节时,只会考虑最后一个字节以及最后一个字节 MSB,

        以“-130”短为例,它可能像下面这样存储

        (MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110
        

        现在字节转换采用最后一个字节,即 0111 1110。(0-MSB) 由于 MSB 表示它是 +ve 值,因此将按原样使用。 是 126。(+ve)。

        再举个“130”短的例子,它可能像下面这样存储

          0-000 000 1000 0010     (MSB = 0)
        

        现在字节转换采用最后一个字节,即 1000 0010 。 (1=MSB) 由于 MSB 表示它是 -ve 值,因此将执行 2 的补码并返回负数。所以在这种情况下,将返回 -126。

         1-000 0010  -> (1's complement) -> 1-111 1101 
                     -> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110
                       = -126
        

        (int)(char)(byte) -1 AND (int)(short)(byte) -1 之间的差异

        (byte)-1       -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111
        (char)(byte)-1 -> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 
        

        类似

        (short)(byte)-1-> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 
        

        但是

        (int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111  = 65535
        since char is unsigned; MSB won't be carry forwarded. 
        

        (int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1
        since short is signed; MSB is be carry forwarded. 
        

        参考文献

        Why is two's complement used to represent negative numbers?

        What is “2's Complement”?

        【解决方案6】:

        最高有效位(第 32 位)表示数字是正数还是负数。如果为 0,则表示该数为正数,并以实际二进制表示形式存储。但如果为 1,则表示该数为负数,并以二进制补码表示形式存储。因此,当我们将权重 -2^32 赋予第 32 位,同时从其二进制表示中恢复整数值时,我们得到了实际答案。

        【讨论】:

          【解决方案7】:

          根据this document,所有整数都经过签名并以二进制补码格式存储在java中。不确定它的可靠性..

          【讨论】:

          • “在二进制补码格式中,正值表示为简单的二进制数。”写在同一个文件中..所以从技术上讲它是正确的。 :)
          【解决方案8】:

          正数直接存储为二进制。负数需要 2 的补语。

          例如:

          15 : 00000000 00000000 00000000 00001111
          -15:11111111 11111111 11111111 11110001

          这是有符号位的区别。

          【讨论】:

            【解决方案9】:

            谢谢dreamcrashhttps://*.com/a/13422442/1065835的回答;在the wiki page 上,他们举了一个例子,帮助我了解如何找出正数的负数对应物的二进制表示。

            例如,使用 1 个字节(= 2 个半字节 = 8 位),十进制数 5 表示为

            0000 01012 最高有效位为 0,因此该模式表示一个 非负值。要以二进制补码表示法转换为 -5, 位被反转; 0变成1,1变成0:

            1111 1010 此时,数字是 十进制值 -5。为了获得二进制补码,将 1 添加到 结果,给出:

            1111 1011 结果是一个有符号二进制数,表示 二进制补码形式的十进制值 -5。最重要的位是 1,所以表示的值为负数。

            【讨论】:

              【解决方案10】:

              对于正整数,2'补码与MSB位0相同(like +14 2'complement is 01110)

              仅对于负整数,我们正在计算 2' 补码 (-14= 10001+1 = 10010)

              所以最终的答案是这两个值(+ve and -ve) 都仅以 2' 补码形式存储。

              【讨论】: