Integer类源码分析

Integer是java中的基础类,在lang包中,它是int类型的包装类。所以还是有必要看下源码的。

一、类继承关系图:

在这里插入图片描述
1、继承了Number抽象类,其实基本类型的包装类除了Boolean外,其他都继承了Number,里面主要一些转换值的方法
2、实现了Comparable接口,说明可以作排序的
3、实现了Serializable接口,可以作序列化

二、继承,实现哪些方法

在这里插入图片描述

三、基本的属性

// integer能表示的最小值 -2147483648
@Native public static final int   MIN_VALUE = 0x80000000;
// integer能表示的最小值 2147483647
@Native public static final int   MAX_VALUE = 0x7fffffff;
//用32位表示数值范围
@Native public static final int SIZE = 32;
//4个字节
public static final int BYTES = SIZE / Byte.SIZE;
//字符数组
final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    };
//取0~99之间数字的十位的数字
final static char [] DigitTens = {
        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
        } ;
//取0~99之间数字的个位的数字
final static char [] DigitOnes = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    } ;

//得到一个数对应得字符串长度 这里用的很巧妙
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

内部私有类:IntegerCache

private static class IntegerCache {
        static final int low = -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");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    //获取配置文件和127之间的最大值
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    //获取缓存范围最大值
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
            //创建缓存
            cache = new Integer[(high - low) + 1];
            int j = low;
            //将数字缓存起来
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

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

        private IntegerCache() {}
    }

从上面可以看出,默认会将-128 ~ 127范围的数字生成Integer对象缓存起来
所以会有:

// A code block
Integer j = 66
Integer k = 66
j == k; // 输出:true

Integer e = 200
Integer h = 200
e == h; //输出:false

因为 j 和 k 都是取得缓存里的,是同一个对象,而 e 和 h 不在缓存里,系统自动装箱new出来的。

基本方法

1、 valueOf(int i) 得到一个Integer对象

public static Integer valueOf(int i) {
	//首先会在缓存中取,否则直接new
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

2、toString方法
上面提到Integer类重写了Object的toString方法,但内部最中还是调了

public static String toString(int i) {
   //最小值
   if (i == Integer.MIN_VALUE)
       return "-2147483648";
   //获取 i 对应的字符串长度,如果是负数符号位也算1个长度
   int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
   //创建字符数组
   char[] buf = new char[size];
   //获取 i 对应的字符数组
   getChars(i, size, buf);
   return new String(buf, true);
}

接下来看getChars方法

static void getChars(int i, int index, char[] buf) {
    int q, r;
    int charPos = index;
    char sign = 0;//符号位

    if (i < 0) {
        sign = '-';
        i = -i;//变成正整数
    }

    //当大于65536的时候每两位开始操作 假设i=65536
    while (i >= 65536) {
    	 //65536 / 100 = 655
        q = i / 100;
    	//65536 - 655*100 = 36  这里使用了技巧,(q << 6) + (q << 5) + (q << 2)相
    	//于q*100, 同时也证明位移和加法性能高于乘法
        r = i - ((q << 6) + (q << 5) + (q << 2));
        i = q;
        //得到36的个位6,放数组到最后一位
        buf [--charPos] = DigitOnes[r];
        //得到36的个位3,依次放入
        buf [--charPos] = DigitTens[r];
    }

    //对于较小的数字,请切换到快速模式,一位一位处理
    // assert(i <= 65536, i);
    for (;;) {
	    //相当于除以10 同时证明乘法和移位的效率要高于除法, 这里用(16+3),是因为最接近
	    //除以10的效果			   
	    q = (i * 52429) >>> (16+3);
	    // r = i-(q*10)  (q << 3) + (q << 1)相当于q*10...
	    r = i - ((q << 3) + (q << 1));  
	    buf [--charPos] = digits [r];//放到数组
	    i = q;
	    if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;//把符号放入
    }
}

从上面的方法可以看到除了代码写的十分优雅、飘逸,对性能的要求是十分苛刻,那怕最求那一点点的速度。

未完待续!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页