我正在学习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);
正在转换字节和短整数,并在不转换整数的情况下提供最小的字节和最小的短值。
它抛出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)
如果我评论这3条整数转换行:-
// 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
这很好。我已经检查了两次字符串的长度,这是32位长度,整数在Java中是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
我对此感到困惑。 请告诉我为什么会引发NumberFormatException以及此问题的解决方案。
答案 0 :(得分:3)
简短回答:
Integer.parseInt()方法(由Integer.valueOf()调用的方法)要求您告诉数字是否为负数,因为它不是设计用来处理带符号的数字。通过添加减号“固定”您的代码:
Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
System.out.println(sInt); // prints -2147483648
长答案:
您的stacktrace会告诉您在哪里可以找到问题所在。您的Integer.valueOf()方法将调用Integer.parseInt(),这将在583行上引发NumberFormatException。您可以在openjdk中找到Integer类的代码。
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(超过MIN_VALUE的一个)!同样,multmin为-1073741823。在循环的第一次迭代中,结果为0,因此result * radix为0,数字为1(这是我们字符串中的第一个数字),因此结果-数字为-1。在第二次迭代中,digit变为0,但是现在结果*基数为-2。在第三次迭代中,我们得到-4,然后是-8,依此类推...一直持续到结果等于-1073741824,这比我们的极限小一。
现在,我们还可以看到该方法检查是否在数字上添加了符号(+或-)。有趣的是,如果我们加上减号,我们会看到该限制设置为MIN_VALUE。因此,违反直觉,我们可以通过添加减号来简单地“修复”您的代码:
Integer sInt = Integer.valueOf("-10000000000000000000000000000000", 2);
System.out.println(sInt); // prints -2147483648
另一方面,您在此处进行了一些奇怪的转换。代替:
sByte= (byte)(int)Integer.valueOf("10000000", 2);
您应该能够写:
sByte = Byte.valueOf("10000000", 2);
我说“应该”,因为实际上你做不到。这导致另一个异常!这是因为Byte.valueOf()方法只调用Integer.valueOf()方法,然后将答案转换为Byte!而且因为整数的10000000为000 ... 00010000000 = 128,它将告诉您对于一个字节来说太大了。
哇!那么,为什么您怪异的铸造技巧起作用了?因为所谓的“无声溢出”。 Java意识到您迫切希望将数字128容纳在一个字节中,这是不可能的,因此它将尽可能多的数字放入其中(127),并通过添加其余的1绕到底部,从而使-128 。我想这就是设计静默溢出的目的,但是依赖它绝对不是一个好主意。为了说明您的行中发生的情况:
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()。