不理解Java 2';补语

不理解Java 2';补语,java,int,twos-complement,Java,Int,Twos Complement,我有以下代码: package com.company; import java.net.InetAddress; import java.net.UnknownHostException; public class Main { private final static int broadcast = 0xffffffff; //4294967295, or 255.255.255.255 private final static int firstClassE =

我有以下代码:

package com.company;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Main {

    private final static int broadcast = 0xffffffff;    //4294967295, or 255.255.255.255
    private final static int firstClassE = 0xf0000000;  //4026531840, or 240.0.0.0

    public static int GetIntInetAddress(InetAddress toConvert)
    {
        final byte[] addr = toConvert.getAddress();

        final int ipAddr =
                ((addr[0] & 0xFF) << (3 * 8)) +
                        ((addr[1] & 0xFF) << (2 * 8)) +
                        ((addr[2] & 0xFF) << (1 * 8)) +
                        (addr[3] & 0xFF);

        return ipAddr;
    }

    public static Boolean IsClassEAddress(InetAddress address)
    {
        int curAddr = GetIntInetAddress(address);
        Boolean test1 = curAddr >= firstClassE;
        Boolean test2 = curAddr < broadcast;
        System.out.println(String.format("\ncurAddr: %s, firstClassE: 240.0.0.0, broadcast: 255.255.255.255", address.getHostAddress()));
        System.out.println(String.format("curAddr: %d, firstClassE: %d, broadcast: %d, curAddr >= firstClassE: %s, curAddr < broadcast: %s",
                                         curAddr, firstClassE, broadcast, test1 ? "true" : "false", test2 ? "true" : "false"));
        return (test1 && test2) ? true : false;
    }

    public static void main(String[] args) throws UnknownHostException
    {
        if (IsClassEAddress(InetAddress.getByName("1.0.0.0")))
        {
            // Raise a flag
            System.out.println("Class E IP address detected.");
        }
        if (IsClassEAddress(InetAddress.getByName("250.0.0.0")))
        {
            // Raise a flag
            System.out.println("Class E IP address detected.");
        }
        if (IsClassEAddress(InetAddress.getByName("239.255.255.255")))
        {
            // Raise a flag
            System.out.println("Class E IP address detected.");
        }
        if (IsClassEAddress(InetAddress.getByName("240.0.0.0")))
        {
            // Raise a flag
            System.out.println("Class E IP address detected.");
        }
        if (IsClassEAddress(InetAddress.getByName("240.0.0.1")))
        {
            // Raise a flag
            System.out.println("Class E IP address detected.");
        }
        if (IsClassEAddress(InetAddress.getByName("255.255.255.255")))
        {
            // Raise a flag
            System.out.println("Class E IP address detected.");
        }
    }
}
package.com公司;
导入java.net.InetAddress;
导入java.net.UnknownHostException;
公共班机{
私有最终静态int-broadcast=0xffffffff;//4294967295或255.255.255.255
私有最终静态int firstClassE=0xf0000000;//4026531840或240.0.0.0
公共静态int GetIntInetAddress(InetAddress到转换)
{
最后一个字节[]addr=toConvert.getAddress();
最终int ipAddr=
((addr[0]&0xFF)=firstClassE:true,curAddr=firstClassE:true,curAddr=firstClassE:false,curAddr=firstClassE:true,curAddr=firstClassE:true,curAddr=firstClassE:true,curAddr
我不理解的是,为什么数字和比较不是我期望的结果,但代码产生了我想要的结果。我想这是整个两个补码的事情,我只是因为某种原因没有“得到”。机械地说,我知道它(两个补码)是翻转位并加1,但我不明白的是,如果一些数字颠倒了,为什么我的比较工作正常

例如,在IP 1.0.0的第一次检查中,检查int值16777216是否小于255.255.255的int值,即-1。结果为假,但广播IP在转换为int时明显大于而不是小于1.0.0的IP。同样,1.0.0.0的检查至少为,或更高然后,240.0.0.0返回true,而我们知道情况显然不是这样

我已经检查了边界情况,一切都正常……我只是不明白为什么会这样(我编写了代码,所以请仔细想想!)。如果有一种更明确的方法来确定IP是否在某个范围内失效,我想探讨一下,因为我的方法一定没有意义,尽管有效(或者是否有效?)

在IntelliJ中,这种行为还有一个奇怪的例子。当我检查地址时,检查器会显示正确的值和负值,正如我在下图中用红色箭头突出显示的那样。使用Windows calc,我输入-84并转换为十六进制并收到FFF…FAC。当我输入172时,我只收到AC…为什么我要这样做得到相同的十六进制数,只是在most sig位置前加1

更新


感谢所有耐心的讨论和精彩的回答!我想我已经了解了这件事的原理,但仍在努力解决使用的微妙之处。:)干杯!

你是对的,这是一个二元补码的问题,我只能建议你仔细阅读并最终得到它-它会在各种整数溢出问题中一次又一次地困扰你(它甚至在一些核心Java库中使用)

问题本身是,在Java中,Integer包含从-(2^31)到(2^31)-1的数字。255*255*255*255的值是2^32-1。它不能表示为带符号的整数。因此,当您将IP转换为带符号的整数时,您不会得到(对您而言)合理的值值。如果要将IP与内置的“小于”进行比较,请在IP实际适合的位置使用原语,如
long


第二部分也发生了同样的事情。一个有符号的
字节
保存从-128到127的值。你把255放在那里。你为什么期望一个正常的结果呢?现在如果你在字节保存0..255的地方使用无符号算术,一切都很好。

在32位2的补码中,非负整数是
0x00000000
-
0x7fffffff
并且这些以普通方式从十六进制转换为十进制

机器中的最低(即最负)数字表示为
0x8000000
(即最高阶位,未设置其他位)。设置此位的真正含义是将31个低阶位指示的正整数添加到数字
-(0x8000000)

练习:32位2的补码中的数字-84是什么?因为它是负数,我们必须设置高阶位。因此,我们从
-(0x8000000)=-2147483648
开始。现在您可以用代数方法解出其他31位所需的值:

-2147483648 + x = -84
=> x = 2147483648 - 84
=> x = 2147483564
=> x = 0x7fffffac
很明显,如果你取
0x8000000 | 0x7fffffac
,你会得到
0xffffffac

显然,
0x7fffffac=(0x7f000000+0xff0000+0xff00+0xac)
和括号中的表达式相当于
(2130706432+16711680+65280+172)
。如果不考虑其他3个字节,低位字节相当于十进制
172
,这一事实毫无意义

您的比较

现在您提到您的比较“不是您期望的结果”。我不知道您期望它们是什么,因为您没有解释,但我猜您希望IP地址的返回值在
[240.0.0.0..255.255.255.255)
不包括范围的右侧。这意味着范围
[0xf0000000..0xFFFFFF]中的IP地址不包括在内

如果这些是32位2的
-2147483648 + x = -84
=> x = 2147483648 - 84
=> x = 2147483564
=> x = 0x7fffffac
    final long ipAddr =
            (((long)addr[0] & 0xFF) << (3 * 8)) +
            (((long)addr[1] & 0xFF) << (2 * 8)) +
            (((long)addr[2] & 0xFF) << (1 * 8)) +
            ((long)addr[3] & 0xFF);
static int compareUnsigned(int x, int y) {
    if (x >= 0 && y < 0) {
        return -1;        // y is actually greater than x if unsigned
    }
    else if (x < 0 && y >= 0) {
        return 1;         // x is greater than y if unsigned
    } else {
        return Integer.compare(x, y);
    }
}
static int compareUnsigned(int x, int y) {
    if (((x ^ y) & 0x80000000) != 0) {  // see if x and y have different signs
        return (x < 0) ? 1 : -1;     
    } else {
        return Integer.compare(x, y);
    }
}
static int compareUnsigned(int x, int y) {
    return Integer.compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE);
}
public static Boolean IsClassEAddress(InetAddress address)
{
    int curAddr = GetIntInetAddress(address);
    return ((curAddr & 0xF0000000) == 0xF0000000) && (curAddr != 0xFFFFFFFF);
}