Integer源码分析

Integer

  1. Integer是int的包装类而int是一种基本数据类型。
  2. Integer是面向对象的,所以必须实例化。
  3. Integer是对象的引用。int则是存储数据。

类图

1.png
public final class Integer extends Number implements Comparable<Integer> {
    // 
}
  1. final 修饰 Integer类没有子类,类中方法默认都是final(final方法不能被子类覆盖)
  2. Integer 继承了 Number类则可使用Number类中方法
  3. Integer 实现了Comparable 接口,所以实现了compareTo方法。

属性

private属性

//真正存储int值
private final int value;
//序列化相关,Integer实现了 Serializable
@Native private static final long serialVersionUID = 1360826667806852920L;

public属性

//int 最小值
@Native public static final int   MIN_VALUE = 0x80000000;
//int 最大值
@Native public static final int   MAX_VALUE = 0x7fffffff;
//int
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
//int bit 位数
@Native public static final int SIZE = 32;
//int byte 位数
public static final int BYTES = SIZE / Byte.SIZE;

构造方法

public Integer(int value) {
    this.value = value;
}
//根据string参数构造新Integer对象
public Integer(String s) throws NumberFormatException {
    // 10 string转int默认为10进制
    this.value = parseInt(s, 10);
}

常见方法

parseInt()

返回一个int基本数据类型

//返回一个十进制的int
public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s,10);
}
//返回一个指定进制的int
//该方法会抛出NumberFormatException 
// 1. 字符串参数为null
// 2. radix 小于 Character.MIN_RADIX 或者大于 Character.MAX_RADIX
// 3. 字符串不是int类型数据
// 4. 指定进制无法表达字符串
public static int parseInt(String s, int radix) throws NumberFormatException{
}

valueOf()

返回一个Integer对象

// 返回一个十进制Integer
public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}
// 返回一个指定进制Integer
public static Integer valueOf(String s, int radix) throws NumberFormatException {
    // parseInt()
    return Integer.valueOf(parseInt(s,radix));
}
// 内部类 Integer 缓存
public static Integer valueOf(int i) {
    // 如果 i 在 IntegerCache 之间,则返回缓存中取出。
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // 默认最大缓存值
        int h = 127;
        // 读取设置的最大缓存值
        String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                // 设置最大值小于127 则最大值为默认值 127
                // 设置最大值为Integer.MAX_VALUE 则最大值为 Integer.MAX_VALUE - 128 - 1
                i = Math.max(i, 127);
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // 传入的数值不能解析为int,忽略。最大值为默认值 127
            }
        }
        high = h;
        // 初始化缓存数组,长度为 127 + 128 + 1
        cache = new Integer[(high - low) + 1];
        //循环初始化 Integer 对象,并放入缓存数组
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // assert 断言关键字
        assert IntegerCache.high >= 127;
    }
    // 空构造
    private IntegerCache() {}
}

valueOf(String s)valueOf(String s, int radix)这两个将字符串转换为Integer对象的方法实现很简单。

主要是涉及到缓存内部类的`方法。

Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

当程序使用第一次使用Integer.valueOf()是则会缓存 -127 到 128 到IntegerCache.cache数组中(缓存的是Integer对象)。

注意:构造函数不会使用缓存。

Integer a = 10;自动装箱编译后Integer b = Integer.valueOf(10);

所以当初始化Integer对象时优先使用Integer a = 10;

设置最大缓存值方式

-Djava.lang.Integer.IntegerCache.high=1000
-XX:AutoBoxCacheMax=1000

例子
public static void main(String[] args) {
    Integer integer1 = 100; // 无缓存,Integer.valueOf(100); new Integer() 放入缓存。
    Integer integer2 = 100; // 缓存中读取。同一个Integer对象
    Integer integer3 = new Integer(100); // 构造函数不会使用缓存

    if(integer1 == integer2){
        System.out.println("integer1 == integer2");
    }else{
        System.out.println("integer1 != integer2");
    }

    if(integer1 == integer3){
        System.out.println("integer1 == integer3");
    }else{
        System.out.println("构造函数不会使用缓存");
        System.out.println("integer1 != integer3");
    }

    if(integer2 == integer3){
        System.out.println("integer2 == integer3");
    }else {
        System.out.println("构造函数不会使用缓存");
        System.out.println("integer2 != integer3");
    }

    Integer integer5 = 300; // 缓存默认缓存 -127 到 128
    Integer integer6 = 300; // 超出缓存

    if(integer5 == integer6){
        System.out.println("integer5 == integer6");
    }else{
        System.out.println("integer5 != integer6");
    }
}
IntegerCache1.png

IntegerCache2.png

decode()

//接受十进制、十六进制、八进制字符串,返回Integer对象
//通过截取字符串获取进制。然后调用valueOf()
public static Integer decode(String nm) throws NumberFormatException {}

最终调用valueOf()方法,故而使用缓存。

getInteger()

// 根据key读取系统属性值。并转为Integer对象
public static Integer getInteger(String nm) {
    return getInteger(nm, null);
}
// 如果系统属值不存在则返回默认值 val
public static Integer getInteger(String nm, int val) {
    Integer result = getInteger(nm, null);
    return (result == null) ? Integer.valueOf(val) : result;
}
public static Integer getInteger(String nm, Integer val) {
    String v = null;
    try {
        //读取系统属性
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    //系统属性不存在则返回 val
    if (v != null) {
        try {
            return Integer.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    return val;
}

最终调用valueOf(),故而使用缓存。

toString()

public static String toString(int i) !
    //i为最小值直接返回
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    // 返回整数 i 位数
    // ① 如果 i 为负数 则转为正整数。前方代码 i 为最小值是转为正整数会溢出。
    // ② 假设 i 等于 10 则 9 < x < 99 。i 循环到 1 ,返回 i + 1 ,10 为2位数。
    // ③ 假设 i 等于 -10 ,+1 是标示负号。-10 为3位数 
    // 设计真精妙啊
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); 
    // 创建一个位数长度的char数组
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };

// ② 假设 i 等于 10 则 9 < x < 99 。i 循环到 1 ,返回 i + 1 ,x 位数 2 。
static int stringSize(int x) {
    // i ++ 进行无限循环
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}
// i 参数,index i 位数,buf index 长度的char数组
static void getChars(int i, int index, char[] buf) {
    int q, r;
    int charPos = index;
    char sign = 0;

    if (i < 0) {
        sign = '-';
        i = -i;
    }

    // Generate two digits per iteration
    // 当 i 大于等于 65536 时,每循环一次将 i 最后两位存到 buf 数组中
    while (i >= 65536) {
        // 除法 假如 i 为 65536 q = 655
        q = i / 100;
        // 相当于  r = i - (q * 100);
        // r = 36
        r = i - ((q << 6) + (q << 5) + (q << 2));
        //将i设置为取出 最后两位的数字
        i = q;
        //从数组中获取两位char数值存入buf
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // 当 i 小于 65536 时 循环剩余位 存到 buf 数组 中
    // 以上代码将 65536 最后两位存入 buf 后,i = 655
    for (;;) {
        // 相当于 q = i / 10。此时 q = 65 
        q = (i * 52429) >>> (16+3);
        // 相当于 r = i-(q*10) 。此时 r = 5
        r = i - ((q << 3) + (q << 1)); 
        // 将 i 最后一位存入 buf
        buf [--charPos] = digits [r];
        // 设置 i 为剩余 数字,然后下次循序
        i = q;
        // i == 0 循环结束,将所有数字拆分存入 buf 中
        if (i == 0) break;
    }
    if (sign != 0) {
        //存入负号
        buf [--charPos] = sign;
    }
    // 36 位是 3 
    // 36 / 10 结果是 3
    final static char [] DigitTens = {
        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',// 0 - 9
        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',// 10 - 19
        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',// 20 - 29
        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',// 30 - 39
        '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',
        } ;
    // 36 位 取出是 6。
    // 36 % 10 余数 6
    final static char [] DigitOnes = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 0 - 9
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 10 - 19
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 20 - 29
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',// 30 - 39
        '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',
        } ;
}

代码上方基本上每一步的注释都有写,debug几次就好了。

int i = 65536;
int q = i / 100;
int r = i - ((q << 6) + (q << 5) + (q << 2));
System.out.println(i);
System.out.println(r);
System.out.println("r = "+ i % 100);

上方代码是从getChars()i >= 65536后的一段代码,发现使用了众多的位运算得到的结果其实和除法求余是一样的。

使用位运算的原因就是要比直接乘除效率要高

其他基本类型

Byte

基本和Integer大同小异。

  1. 同样是final修饰
  2. 继承了Number实现了Comparable

parseByte()

 public static byte parseByte(String s, int radix) throws NumberFormatException {
     //将字符串转为 int 
     int i = Integer.parseInt(s, radix);
     // 如果超出 byte 范围 抛出异常
     if (i < MIN_VALUE || i > MAX_VALUE)
         throw new NumberFormatException(
         "Value out of range. Value:\"" + s + "\" Radix:" + radix);
     // 向下转换
     return (byte)i;
 }

valueOf()

public static Byte valueOf(byte b) {
    final int offset = 128;
    //同样是从内部缓存类中读取
    return ByteCache.cache[(int)b + offset];
}
 private static class ByteCache {
     private ByteCache(){}
     
     static final Byte cache[] = new Byte[-(-128) + 127 + 1];
     // 默认缓存 -128 到 127 数字
     static {
         for(int i = 0; i < cache.length; i++)
             cache[i] = new Byte((byte)(i - 128));
     }
 }

Short

参考Byte和Integer

Long

参考Byte和Integer

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容