代码之家  ›  专栏  ›  技术社区  ›  Dhiresh Budhiraja

将二进制字符串转换为整数时出现NumberFormatException

  •  2
  • Dhiresh Budhiraja  · 技术社区  · 6 年前

    我正在学习java中的位操作。所以,我把二进制字符串转换成整数字节和短。 这是我的程序:-

    byte sByte,lByte; // 8 bit
    short sShort,lShort; // 16 bit
    int sInt,lInt; // 32 bit
    sByte= (byte)(int)Integer.valueOf("10000000", 2); //Smallest Byte
    lByte= (byte) ~sByte;
    sShort= (short)(int)Integer.valueOf("1000000000000000", 2); //Smallest Short
    lShort = (short) ~sShort;
    sInt = (int) (int)Integer.valueOf("10000000000000000000000000000000", 2); //Smallest Int
    lInt= (int)~sInt;
    System.out.println("\"10000000\" \"8 bit\" byte=>"+sByte+"\t~byte=>"+lByte);
    System.out.println("\"1000000000000000\" \"16 bit\" short=>"+sShort+"\t~short=>"+lShort);
    System.out.println("\"10000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);
    

    Byte和Short正在转换,并给出最小的Byte和最小的Short值,而Integer没有转换。

    它引发NumberFormatException,如下所示:-

    Exception in thread "main" java.lang.NumberFormatException: For input string: "10000000000000000000000000000000"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.lang.Integer.parseInt(Integer.java:583)
        at java.lang.Integer.valueOf(Integer.java:740)
        at com.learnjava.BitsManipulation.start(BitsManipulation.java:14)
        at com.learnjava.learnjava.main(learnjava.java:9)
    

    //    sInt = (int) (int)Integer.valueOf("10000000000000000000000000000000", 2); //Smallest Int
    //    lInt= (int)~sInt;
    //    System.out.println("\"10000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);
    

    它给了我输出:-

    "10000000" "8 bit" byte=>-128   ~byte=>127
    "1000000000000000" "16 bit" short=>-32768   ~short=>32767
    

    很好,我已经检查了字符串的长度两次,在java中是32位的长度,整数是32位的,这样它应该可以工作,而这里不是这样。

    如果我从32长度的字符串中删除一个0或1,或者将1替换为0,那么它也可以工作,如下所示:-

    sInt = (int) (int)Integer.valueOf("00000000000000000000000000000000", 2); //Smallest Int
    lInt= (int)~sInt;
    System.out.println("\"00000000000000000000000000000000\" \"32 bit\" int=>"+sInt+"\t~int=>"+lInt);
    
    
    sInt = (int) (int)Integer.valueOf("1000000000000000000000000000000", 2); //Smallest Int
    lInt= (int)~sInt;
    System.out.println("\"1000000000000000000000000000000\" \"31 bit\" int=>"+sInt+"\t~int=>"+lInt);
    

    "00000000000000000000000000000000" "32 bit" int=>0  ~int=>-1
    
    "1000000000000000000000000000000" "31 bit" int=>1073741824  ~int=>-1073741825
    

    我对这件事感到困惑。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Jasper    6 年前

    简短回答:

    Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
    System.out.println(sInt); // prints -2147483648
    

    你的stacktrace告诉你哪里可以找到哪里出了问题。你的Integer.valueOf()方法调用Integer.parseInt(),这又在第583行抛出NumberFormatException。您可以在 openjdk .

    public static int parseInt(String s, int radix) throws NumberFormatException {
        int result = 0;
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;
    
        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);
            }
    
            multmin = limit / radix;
            while (i < len) {
                digit = Character.digit(s.charAt(i++),radix);
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                result -= digit;
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }
    

    我已经删除了代码中当前示例没有运行的部分。请注意,限制为-2147483647(超过最小值的一个)!同样,multmin is-1073741823。在循环的第一次迭代中,result是0,所以result*基数是0,digit是1(这是字符串中的第一个数字),所以result-digit是-1。在第二次迭代中,数字变成0,但现在结果*基数是-2。在第三次迭代中,我们得到-4,然后是-8,等等。。。这个过程一直持续到结果等于-1073741824,这比我们的极限值少了一个。

    现在,我们还可以看到该方法检查是否在数字中添加了符号(+或-)。有趣的是,如果我们加上一个负数,我们会看到这个极限被设置为minu值。因此,与直觉相反,我们可以简单地通过添加减号来“修复”代码:

    整数sInt=Integer.valueOf("-10000000000000000000000000000000", 2);
    System.out.println(新加坡);//印刷品-2147483648
    

    另一方面,你做了一些奇怪的铸造。而不是:

    sByte= (byte)(int)Integer.valueOf("10000000", 2);
    

    你应该能够写:

    sByte = Byte.valueOf("10000000", 2);
    

    我说“应该”,因为实际上你不能。这将导致另一个例外!这是因为Byte.valueOf()方法简单调用Integer.valueOf()方法,然后将答案强制转换为一个字节!因为一个整数的10000000是000…00010000000=128,它会告诉你对于一个字节来说太大了。

    哇!那你那奇怪的施法技巧为什么管用呢?因为一种叫做“无声溢出”的东西。Java意识到您非常希望将数字128放入一个字节中,这是不可能的,因此它将尽可能多的数字放入其中(127),并通过将剩余的1加起来,将数字压缩到底部,剩下的是-128。我想这就是silent overflow的设计目的,但是依赖它肯定是个坏主意。为了说明在你的队伍中发生了什么:

    sByte= (byte)(int)Integer.valueOf("10000000", 2);
    
    Integer a = Integer.valueOf("10000000", 2);
    System.out.println(a);        // 128
    int b = (int)a;
    System.out.println(b);        // 128
    byte sByte = (byte)b;
    System.out.println(sByte);    // -128
    

    所以,不要对有符号的数字使用parseInt()或valueOf()。

    推荐文章