java 8 关于 Integer.parseUnsignedInt(String s, int radix)

DancyLon 2017-03-24 10:15:03
今天发现一个问题,我想把一个32位的二进制字符串转成一个整数,于是用了下面的方法

String binary="11000000101010000000000100000001";
int ipnum = Integer.parseUnsignedInt(binary,2);
System.out.println(ipnum);

然后发现这个方法是1.8新增的,返回无符号整数。但是这个结果却是有符号的。
如果用原来的方法呢

String binary="11000000101010000000000100000001";
int ipnum = Integer.parseInt(binary,2);
System.out.println(ipnum);

就会报错,这个是什么情况啊?
...全文
2278 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
DancyLon 2017-03-24
  • 打赏
  • 举报
回复
是不是int类型的就没有无符号数这一回事啊
ZeWe 2017-03-24
  • 打赏
  • 举报
回复
except that the first character may be an ASCII plus sign '+' ('\u002B'). The resulting integer value is returned.


可能是第一个ASCII为加号“+”
逗泥丸的平方 2017-03-24
  • 打赏
  • 举报
回复
引用 5 楼 zs808 的回复:
[quote=引用 3 楼 qq_35209952 的回复:]

if (firstChar == '-') {
                throw new
                    NumberFormatException(String.format("Illegal leading minus sign " +
                                                       "on unsigned string %s.", s));
            } 
去看代码呀
你贴错代码了吧。。。 [/quote] 看起来是的. .. 大概我当时觉得这段很好笑.
DancyLon 2017-03-24
  • 打赏
  • 举报
回复
引用 9 楼 zs808 的回复:
看来我在码parseUnsignedInt为负原因的时候lz已经自己找到答案了,恭喜恭喜
s 哈哈,同样感谢你的回答
DancyLon 2017-03-24
  • 打赏
  • 举报
回复
并不像我想的那样,我以为32个1无符号数就可以得到2(32)-1了
zs808 2017-03-24
  • 打赏
  • 举报
回复
看来我在码parseUnsignedInt为负原因的时候lz已经自己找到答案了,恭喜恭喜
zs808 2017-03-24
  • 打赏
  • 举报
回复
补充说明一下,关于parseUnsignedInt返回有符号数字的原因: 同样的,我们来看看parseUnsignedInt的代码:

public static int parseUnsignedInt(String s, int radix)
                throws NumberFormatException {
        if (s == null)  {
            throw new NumberFormatException("null");
        }

        int len = s.length();
        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar == '-') {
                throw new
                    NumberFormatException(String.format("Illegal leading minus sign " +
                                                       "on unsigned string %s.", s));
            } else {
                if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
                    (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
                    return parseInt(s, radix);
                } else {
                    long ell = Long.parseLong(s, radix);
                    if ((ell & 0xffff_ffff_0000_0000L) == 0) {
                        return (int) ell;
                    } else {
                        throw new
                            NumberFormatException(String.format("String value %s exceeds " +
                                                                "range of unsigned int.", s));
                    }
                }
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
    }
注意这两句:

 long ell = Long.parseLong(s, radix);
                    if ((ell & 0xffff_ffff_0000_0000L) == 0) {
                        return (int) ell;
                    } else {
                        throw new
                            NumberFormatException(String.format("String value %s exceeds " +
                                                                "range of unsigned int.", s));
                    }
这里,首先进行parseLong,因为你的二进制数据是32位,没有导致溢出,所以这句会返回3232235777 但是,这个数字已经是超出Int的表示范围了,所以在执行

(int) ell  //(int)3232235777L
强转时,就发生了溢出,结果就是负的了。(具体的原理就不说了,lz可以百度java数值类型转换溢出处理) 给个传送门吧: http://blog.csdn.net/u011637069/article/details/46786679
DancyLon 2017-03-24
  • 打赏
  • 举报
回复
#5楼说的对。 我也看了看源码,对于parseInt(String s, int radix)方法,32位以下的二进制字符串,不用加‘+’或‘-’号,因为它会默认你是正的。 但是对于32位的,你的左起第一位必须是‘+’或‘-’号。 但是对于parseUnsignedInt(String s, int radix)方法,


         public static int parseUnsignedInt(String s, int radix)
                throws NumberFormatException {
        if (s == null)  {
            throw new NumberFormatException("null");
        }

        int len = s.length();
        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar == '-') {
                throw new
                    NumberFormatException(String.format("Illegal leading minus sign " +
                                                       "on unsigned string %s.", s));
            } else {
                if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
                    (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
                    return parseInt(s, radix);
                } else {
                    long ell = Long.parseLong(s, radix);
                    if ((ell & 0xffff_ffff_0000_0000L) == 0) {
                        return (int) ell;
                    } else {
                        throw new
                            NumberFormatException(String.format("String value %s exceeds " +
                                                                "range of unsigned int.", s));
                    }
                }
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
    }
        
看到这个return (int) ell; 了吧,它是由long转化来的,也就是它还是默认32位的左起第一位是符号位,1就是负,0就是正。
DancyLon 2017-03-24
  • 打赏
  • 举报
回复
我知道了,32位的时候,无符号整型第一位默认是符号位
zs808 2017-03-24
  • 打赏
  • 举报
回复
引用 3 楼 qq_35209952 的回复:

if (firstChar == '-') {
                throw new
                    NumberFormatException(String.format("Illegal leading minus sign " +
                                                       "on unsigned string %s.", s));
            } 
去看代码呀
你贴错代码了吧。。。 关于lz的问题,就要针对Integer.parseInt的实现来说了。 这应该也可以说是Integer.parseInt的一个BUG吧,Integer.parseInt对于“符号位”的确定是按照“正负”来的。也就是说,就算你的redix是2,你也要把符号位设置成"+"或者是“-”。 以下是Integer.parseInt的实现代码:

    public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * WARNING: This method may be invoked early during VM initialization
         * before IntegerCache is initialized. Care must be taken to not use
         * the valueOf method.
         */

        if (s == null) {
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

        int result = 0;
        boolean negative = false;
        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);

                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            multmin = limit / radix;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }
lz代码在1.8下,会在


                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
这行出错。 下面来分析分析为什么会在这行出错。 通过上面贴出来的代码,不难发现,parseInt的过程起始很简单,首先判断第一个字符是不是“+或者-”如果是"-",则说明值是负的,否则,值就是正的。 好,这个逻辑在非二进制环境下没有问题,因为非二进制表示的int变量,都是会用“-”来表示负数。 然而,在二进制条件下,符号位的影响就出来了,因为二进制不是通过“+,-”来区分正负,而是通过第一位“是1还是0”来判断正负。所以,在parseInt时,由于将符号位也当做实际的值计算进去了,所以就导致计算溢出,出错了。。。。 解决办法就是把二进制的第一位的“0,1”改成“-,+”,就可以了:

	public static void main(String[] args) {
		String binary = "+1000000101010000000000100000001"; // 11000000101010000000000100000001
		int ipnum = Integer.parseInt(binary, 2);
		System.out.println(ipnum);
		binary = "-1000000101010000000000100000001"; // 01000000101010000000000100000001
		ipnum = Integer.parseInt(binary, 2);
		System.out.println(ipnum);
	}
ps45221 2017-03-24
  • 打赏
  • 举报
回复
Java中int的有符号的,没有无符号的,只能用更大的long,BigInteger来表示
逗泥丸的平方 2017-03-24
  • 打赏
  • 举报
回复

if (firstChar == '-') {
                throw new
                    NumberFormatException(String.format("Illegal leading minus sign " +
                                                       "on unsigned string %s.", s));
            } 
去看代码呀

62,635

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧