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

7人阅读 评论(0) 收藏 举报
分类:

今天带来的是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=<size>
     */

    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源码分析(一)——String

String的源码分析 Java中String不是基本数据类型,而是一种特殊的类。String代表的是不可变的字符序列,为不可变对象,一旦被创建,就不能修改它的值,对于已经存在的String对象的修...
  • lu1005287365
  • lu1005287365
  • 2016-08-23 09:25:55
  • 858

《Java源码分析》:Condition

《Java源码分析》:Condition如下这篇博文讲解的Condition真心将的好,自己结合了源码也基本上对Condition有了一个大致的了解。写篇博客记录下。参考博客地址如下:http://i...
  • u010412719
  • u010412719
  • 2016-08-01 22:01:03
  • 3924

Java源码解析(5) —— Class(4)

Class最后一部分源码,这一部分大都是private方法、属性、类,都是Class本身各种方法的实现细节,涉及到了很多Class的实现原理,较为深奥,网上能找到的资料也比较少,目前只懂皮毛,仅供参考...
  • a327369238
  • a327369238
  • 2017-02-13 17:59:07
  • 601

Java源码侦探--异常体系解读Throwable

Throwable类是整个异常体系类的父级类,当然最终追根溯源到底的父类当然要归于Object类。Throwable类实现了Serializable接口,表示Throwable可以进行序列化,继承自O...
  • wangyang1354
  • wangyang1354
  • 2016-12-02 21:21:37
  • 1536

【JDK】:java.lang.Integer源码解析

本文对JDK8中的java.lang.Integer包装类的部分数值缓存技术、valueOf()、stringSize()、toString()、getChars()、parseInt()等进行简要分...
  • u011080472
  • u011080472
  • 2016-05-14 18:45:50
  • 741

《Java源码分析》:Java NIO 之 Buffer

《Java源码分析》:Java NIO 之 Buffer在上篇博文中,我们介绍了Java NIO 中Channel 和Buffer的基本使用方法,这篇博文将从源码的角度来看下Buffer的内部实现。在...
  • u010412719
  • u010412719
  • 2016-10-10 10:46:26
  • 3154

【jdk1.8】Integer源码分析

先看下Integer的类声明:public final class Integer extends Number implements Comparable同样地,Integer是一个不变类,实现了C...
  • moqihao
  • moqihao
  • 2016-03-24 10:34:43
  • 667

JDK 源码解析 —— Integer

零. 简介 对于 Integer 这个 Java 程序员几乎天天使用的类, 使用上却可以看出普通程序员和优秀程序员区别。 一. 深入代码 在创建数...
  • wenniuwuren
  • wenniuwuren
  • 2015-10-27 21:12:21
  • 4492

Java源码分析:关于 HashMap 1.8 的重大更新

前言 HashMap 在 Java 和 Android 开发中非常常见 而HashMap 1.8 相对于 HashMap 1.7 更新多 今天,我将通过源码分析HashMap 1.8 ,从而讲...
  • carson_ho
  • carson_ho
  • 2018-02-26 08:58:44
  • 13071
    个人资料
    持之以恒
    等级:
    访问量: 778
    积分: 244
    排名: 33万+
    文章分类
    文章存档