7

我没有学习 IT,直到最近才遇到移位和二进制补码的应用程序。那么,您能否在解释中使用简单的英语,并假设我对 IP 地址、位操作和 Java 数据类型几乎一无所知?

今天,我发现了以下一段代码(缩写):

long m = (-1) << (byte) 16;

现在,这是用于 IP 子网掩码。我知道我需要从 4 个 8 位块(即 4 个字节)开始,并且所有位都必须“打开”:11111111 11111111 1111111 1111111接下来,从右侧移入零,在这种情况下是 16 位的值;所以我们得到11111111 11111111 00000000 0000000了,面具。

但我确实有几个问题:

  1. 16必须是类型byte才能工作吗?
  2. 结果是类型long。当上面的表达式运行时,-1被转换为 - 有效 - 4x8bit 块。在应用二进制补码时,Java 如何知道它需要 32 个位置/位(IP 地址的长度),而不是 16 或 8 个?(我猜这与long数据类型有关?)
  3. 为什么二进制补码应用于-1开头?-0b1(如果你问它二进制是什么,谷歌会给你-1。我首先认为这可能与溢出有关,但事实并非如此,是不是......?)
  4. 真的,编译器在运行代码时会将其转换为什么数据类型,以使其正常工作?

更新:16方法在运行时产生;我只是在这里放一个常数作为例子。事后看来可能是个坏主意...

4

2 回答 2

6

真的,编译器在运行代码时会将其转换为什么数据类型,以使其正常工作?

这个

(-1) << (byte) 16;

是一个常数表达式。它的值在编译时是已知的。它是long带有值的-65536(以十进制表示)。

如果表达式不是常量表达式,则在计算表达式时变量的类型无关紧要。只有稍后将其值分配给变量时才有意义。

举个例子

int i = -1;
long m = i << (byte) 16;

上面的表达式涉及一个移位运算符和两个操作数,一个是 type int,另一个是 type byte

JLS 声明了以下有关移位运算符及其操作数的内容

一元数字提升 ( §5.6.1 ) 分别在每个操作数上执行。

这是

否则,如果操作数是编译时类型的 byte、short 或 char,则通过扩展原语转换(第 5.1.2 节)将其提升为 int 类型的值。

因此该byte值扩大到int. 所以对你的第一个问题不。

表达式的结果将是类型int(32 位)的值。它必须分配给一个(64 位)变量,因此在分配之前long该值将扩大到 a 。long

再次从JLS

整数类型有 byte、short、int 和 long,其值分别为 8 位、16 位、32 位和 64 位有符号二进制补码整数,以及 char,其值为 16 位无符号整数表示 UTF-16 代码单元(第 3.1 节)。

这就是它们的存储方式。

于 2015-09-08T15:44:34.303 回答
2

您的m变量是long类型实际上令人困惑,因为 IP 地址是 32 位的并且对应于int. 您的右侧确实是int,只有在完全计算后才会扩展到long(64 位)。回答您的问题:

  1. 它没有。您可以删除演员表。
  2. 结果实际上是 type ,但由于 type需要它int而被转换为。longm
  3. 二进制补码并没有“应用于”任何东西,真的。该数字以二进制补码-1形式编码。您需要一些方法来表示只有位的负数。另外,这里的二进制补码起到了辅助作用:它只是-1被编码为全 1 位。
  4. 这只是一个 32 位向左移动的块,零填补了空缺。然后,为了转换为long,在左侧添加了另外 32 个 1 位。
于 2015-09-08T15:41:03.643 回答