【Java源码分析】Integer源码分析

今天带来的是Integer源码的分析。代码已经注释的非常清晰了。

1.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.
         */
        //String转换为Integter,不能是null
        if (s == null) {
            throw new NumberFormatException("null");
        }
        //最小二进制,最大36进制
        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;	//如果是正数negative = false,如果是负数negative = true
        int i = 0, len = s.length();	//i是遍历String的下标,len是长度
        int limit = -Integer.MAX_VALUE;	//限制,不能超过Integer的最大值。负的MAX_VALUE(以下都是再负数范围内进行判断的,为了统一处理,因为正数的最大值转化为负数不会溢出,而负数的最小值转换为正数会溢出,我这里所说的溢出是指的Integer范围内)
        int multmin;	//一个限制,后面讲
        int digit;		//每个字符转换为数字后的值

        //如果是非空字符串
        if (len > 0) {
            char firstChar = s.charAt(0);	
            if (firstChar < '0') { // Possible leading "+" or "-"//ASCII码表小于‘0’的都是字符
                if (firstChar == '-') {		//如果是负号
                    negative = true;	//标志改为负号
                    limit = Integer.MIN_VALUE;		//界限是Integer最小值
                } else if (firstChar != '+')	//如果不是加号,说明第一个符号是个非法字符,抛出异常
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // 不能只有一个 "+" 或者 "-"
                    throw NumberFormatException.forInputString(s);
                i++;	//i指向第一个数字的位置
            }
            //下面就是转换成数字的逻辑了。
            /*有很多小伙伴到这里可能不是很懂。首先limit表示溢出边界范围(这个程序中,无论正负,都统一成了负数),radix表示进制。
            	举个例子:假设十进制,我们到77就代表溢出了,那么multmin = -77 / 10 = -7,为什么要算这个数,是为了后面的操作。*/
            //这里可以用移位操作吧?
            multmin = limit / radix;
            while (i < len) {	//i没越界,执行字符转换成数字
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);	//字符转换成数字
                if (digit < 0) {	//转换出来如果每一位是负数,抛出异常
                    throw NumberFormatException.forInputString(s);
                }
                //关键来了:当前结果是否小于multmin,如果小于,抛出溢出异常。注意multmin一直是负数,如果result比multmin还要小,说明执行 result *= radix 的时候肯定是溢出了(以咱们的例子继续,multmin为-7,result < multmin,假设result为-9,那么执行result *= radix,result变成了-90,就发生了溢出 ),如果不提前抛出异常,那么我们的result中存的是溢出后的结果(结果不准确了)
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;	
                //这里又是一个溢出判断,注意:digit是非负数,result,limit是负数。
                //换成result - digit < limit你可能更好理解,继续我们的例子,假设result = -70,digit = 9, -70 - 9 =- 79, 是小于-77的,这就发生了溢出。
                //但是为什么不换成result - digit < limit呢,因为在这里,做减法可能发生溢出。当我们算出-79的时候,result就已经发生了溢出,所以就将表达式变换了一下result < limit + digit,防止了溢出
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;	//在没有溢出的情况下,算出result
            }
        //如果字符串是空串,直接抛出异常
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;	//判断标志,如果是负数,返回result,如果是正数,返回-result
    }

2.IntegerCache内部类

/**
     * Integer默认缓存-128到127之间的数,缓存在第一次使用时初始化。缓存的大小是可控制的,在server模式下用-XX:AutoBoxCacheMax=
     */

    private static class IntegerCache {
        static final int low = -128;	//注意,这个值自始至终没有变过,所以下限一直是-128
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");	//high的值可以从配置文件中读取
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);	//注意,这里刚开始看可能很突兀,为什么是Integer.MAX_VALUE - (-low) -1呢?因为创建的是一个在low到high范围的Integer数组,如果大于了这个值,那么在为数组分配空间的时候就溢出了
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];	//缓存的最大空间是Integer.MAX_VALUE,这就是为什么h的最大值是Integer.MAX_VALUE - (-low) -1的原因了
            int j = low; 
            for(int k = 0; k < cache.length; k++)	//缓存的最大范围是-128到MAX_VALUE - (-low) -1
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }
3.toString方法
/**
     * 返回第一个参数用第二参数表示的字符串形式,第二个参数是进制数,默认是10进制
     *
     * 如果第一个参数是负的,那么返回结果中第一个字符是'-',如果第一个参数是正的,那么返回的结果中没有符号
     * 结果中剩余的字符表示第一个参数的大小
     *
     * @see     java.lang.Character#MAX_RADIX
     * @see     java.lang.Character#MIN_RADIX
     */
    public static String toString(int i, int radix) {
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
            radix = 10;

        /* Use the faster version */
        if (radix == 10) {
            return toString(i);
        }

        char buf[] = new char[33];	//多存一个负号符号的位置
        boolean negative = (i < 0);
        int charPos = 32;	//最后一个位置

        if (!negative) {	//统一成负数
            i = -i;
        }

        while (i <= -radix) {
            buf[charPos--] = digits[-(i % radix)];   //取余法进行进制转换,从buf的最后向前面添加
            i = i / radix;							//取整数部分
        }							
        buf[charPos] = digits[-i];	//最后剩下一位单独处理

        if (negative) {			//如果是负数就添加'-'号
            buf[--charPos] = '-';
        }

        return new String(buf, charPos, (33 - charPos));
    }

你可能感兴趣的:(java,java源码)