Integer源碼分析

Integer

  1. Integer是int的包裝類而int是一種基本數(shù)據(jù)類型。
  2. Integer是面向?qū)ο蟮?,所以必須?shí)例化。
  3. Integer是對象的引用。int則是存儲(chǔ)數(shù)據(jù)。

類圖

1.png
public final class Integer extends Number implements Comparable<Integer> {
    // 
}
  1. final 修飾 Integer類沒有子類,類中方法默認(rèn)都是final(final方法不能被子類覆蓋)
  2. Integer 繼承了 Number類則可使用Number類中方法
  3. Integer 實(shí)現(xiàn)了Comparable 接口,所以實(shí)現(xiàn)了compareTo方法。

屬性

private屬性

//真正存儲(chǔ)int值
private final int value;
//序列化相關(guān),Integer實(shí)現(xiàn)了 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 位數(shù)
@Native public static final int SIZE = 32;
//int byte 位數(shù)
public static final int BYTES = SIZE / Byte.SIZE;

構(gòu)造方法

public Integer(int value) {
    this.value = value;
}
//根據(jù)string參數(shù)構(gòu)造新Integer對象
public Integer(String s) throws NumberFormatException {
    // 10 string轉(zhuǎn)int默認(rèn)為10進(jìn)制
    this.value = parseInt(s, 10);
}

常見方法

parseInt()

返回一個(gè)int基本數(shù)據(jù)類型

//返回一個(gè)十進(jìn)制的int
public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s,10);
}
//返回一個(gè)指定進(jìn)制的int
//該方法會(huì)拋出NumberFormatException 
// 1. 字符串參數(shù)為null
// 2. radix 小于 Character.MIN_RADIX 或者大于 Character.MAX_RADIX
// 3. 字符串不是int類型數(shù)據(jù)
// 4. 指定進(jìn)制無法表達(dá)字符串
public static int parseInt(String s, int radix) throws NumberFormatException{
}

valueOf()

返回一個(gè)Integer對象

// 返回一個(gè)十進(jìn)制Integer
public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}
// 返回一個(gè)指定進(jìn)制Integer
public static Integer valueOf(String s, int radix) throws NumberFormatException {
    // parseInt()
    return Integer.valueOf(parseInt(s,radix));
}
// 內(nèi)部類 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 {
        // 默認(rèn)最大緩存值
        int h = 127;
        // 讀取設(shè)置的最大緩存值
        String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                // 設(shè)置最大值小于127 則最大值為默認(rèn)值 127
                // 設(shè)置最大值為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) {
                // 傳入的數(shù)值不能解析為int,忽略。最大值為默認(rèn)值 127
            }
        }
        high = h;
        // 初始化緩存數(shù)組,長度為 127 + 128 + 1
        cache = new Integer[(high - low) + 1];
        //循環(huán)初始化 Integer 對象,并放入緩存數(shù)組
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // assert 斷言關(guān)鍵字
        assert IntegerCache.high >= 127;
    }
    // 空構(gòu)造
    private IntegerCache() {}
}

valueOf(String s)valueOf(String s, int radix)這兩個(gè)將字符串轉(zhuǎn)換為Integer對象的方法實(shí)現(xiàn)很簡單。

主要是涉及到緩存內(nèi)部類的`方法。

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

當(dāng)程序使用第一次使用Integer.valueOf()是則會(huì)緩存 -127 到 128 到IntegerCache.cache數(shù)組中(緩存的是Integer對象)。

注意:構(gòu)造函數(shù)不會(huì)使用緩存。

Integer a = 10;自動(dòng)裝箱編譯后Integer b = Integer.valueOf(10);

所以當(dāng)初始化Integer對象時(shí)優(yōu)先使用Integer a = 10;

設(shè)置最大緩存值方式

-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; // 緩存中讀取。同一個(gè)Integer對象
    Integer integer3 = new Integer(100); // 構(gòu)造函數(shù)不會(huì)使用緩存

    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("構(gòu)造函數(shù)不會(huì)使用緩存");
        System.out.println("integer1 != integer3");
    }

    if(integer2 == integer3){
        System.out.println("integer2 == integer3");
    }else {
        System.out.println("構(gòu)造函數(shù)不會(huì)使用緩存");
        System.out.println("integer2 != integer3");
    }

    Integer integer5 = 300; // 緩存默認(rèn)緩存 -127 到 128
    Integer integer6 = 300; // 超出緩存

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

IntegerCache2.png

decode()

//接受十進(jìn)制、十六進(jìn)制、八進(jìn)制字符串,返回Integer對象
//通過截取字符串獲取進(jìn)制。然后調(diào)用valueOf()
public static Integer decode(String nm) throws NumberFormatException {}

最終調(diào)用valueOf()方法,故而使用緩存。

getInteger()

// 根據(jù)key讀取系統(tǒng)屬性值。并轉(zhuǎn)為Integer對象
public static Integer getInteger(String nm) {
    return getInteger(nm, null);
}
// 如果系統(tǒng)屬值不存在則返回默認(rèn)值 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 {
        //讀取系統(tǒng)屬性
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    //系統(tǒng)屬性不存在則返回 val
    if (v != null) {
        try {
            return Integer.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    return val;
}

最終調(diào)用valueOf(),故而使用緩存。

toString()

public static String toString(int i) !
    //i為最小值直接返回
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    // 返回整數(shù) i 位數(shù)
    // ① 如果 i 為負(fù)數(shù) 則轉(zhuǎn)為正整數(shù)。前方代碼 i 為最小值是轉(zhuǎn)為正整數(shù)會(huì)溢出。
    // ② 假設(shè) i 等于 10 則 9 < x < 99 。i 循環(huán)到 1 ,返回 i + 1 ,10 為2位數(shù)。
    // ③ 假設(shè) i 等于 -10 ,+1 是標(biāo)示負(fù)號(hào)。-10 為3位數(shù) 
    // 設(shè)計(jì)真精妙啊
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); 
    // 創(chuàng)建一個(gè)位數(shù)長度的char數(shù)組
    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 };

// ② 假設(shè) i 等于 10 則 9 < x < 99 。i 循環(huán)到 1 ,返回 i + 1 ,x 位數(shù) 2 。
static int stringSize(int x) {
    // i ++ 進(jìn)行無限循環(huán)
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}
// i 參數(shù),index i 位數(shù),buf index 長度的char數(shù)組
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
    // 當(dāng) i 大于等于 65536 時(shí),每循環(huán)一次將 i 最后兩位存到 buf 數(shù)組中
    while (i >= 65536) {
        // 除法 假如 i 為 65536 q = 655
        q = i / 100;
        // 相當(dāng)于  r = i - (q * 100);
        // r = 36
        r = i - ((q << 6) + (q << 5) + (q << 2));
        //將i設(shè)置為取出 最后兩位的數(shù)字
        i = q;
        //從數(shù)組中獲取兩位char數(shù)值存入buf
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // 當(dāng) i 小于 65536 時(shí) 循環(huán)剩余位 存到 buf 數(shù)組 中
    // 以上代碼將 65536 最后兩位存入 buf 后,i = 655
    for (;;) {
        // 相當(dāng)于 q = i / 10。此時(shí) q = 65 
        q = (i * 52429) >>> (16+3);
        // 相當(dāng)于 r = i-(q*10) 。此時(shí) r = 5
        r = i - ((q << 3) + (q << 1)); 
        // 將 i 最后一位存入 buf
        buf [--charPos] = digits [r];
        // 設(shè)置 i 為剩余 數(shù)字,然后下次循序
        i = q;
        // i == 0 循環(huán)結(jié)束,將所有數(shù)字拆分存入 buf 中
        if (i == 0) break;
    }
    if (sign != 0) {
        //存入負(fù)號(hào)
        buf [--charPos] = sign;
    }
    // 36 位是 3 
    // 36 / 10 結(jié)果是 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 余數(shù) 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()當(dāng) i >= 65536后的一段代碼,發(fā)現(xiàn)使用了眾多的位運(yùn)算得到的結(jié)果其實(shí)和除法求余是一樣的。

使用位運(yùn)算的原因就是要比直接乘除效率要高

其他基本類型

Byte

基本和Integer大同小異。

  1. 同樣是final修飾
  2. 繼承了Number實(shí)現(xiàn)了Comparable

parseByte()

 public static byte parseByte(String s, int radix) throws NumberFormatException {
     //將字符串轉(zhuǎn)為 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);
     // 向下轉(zhuǎn)換
     return (byte)i;
 }

valueOf()

public static Byte valueOf(byte b) {
    final int offset = 128;
    //同樣是從內(nèi)部緩存類中讀取
    return ByteCache.cache[(int)b + offset];
}
 private static class ByteCache {
     private ByteCache(){}
     
     static final Byte cache[] = new Byte[-(-128) + 127 + 1];
     // 默認(rèn)緩存 -128 到 127 數(shù)字
     static {
         for(int i = 0; i < cache.length; i++)
             cache[i] = new Byte((byte)(i - 128));
     }
 }

Short

參考Byte和Integer

Long

參考Byte和Integer

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 其他更多java基礎(chǔ)文章:java基礎(chǔ)學(xué)習(xí)(目錄) 轉(zhuǎn)載自 Java 源碼學(xué)習(xí)系列(三)——Integer學(xué)習(xí)的過...
    Hiwayz閱讀 778評(píng)論 0 0
  • Integer 本文源碼基于JDK8 Integer也是我們經(jīng)常使用的工具類、包裝類,此文主要用于記錄學(xué)習(xí)筆記,主...
    luoyoub閱讀 284評(píng)論 1 0
  • 1. 描述 API:int的包裝類型,內(nèi)部包含了一個(gè)int字段。 關(guān)鍵字段: 2. 構(gòu)造函數(shù) 第一種 直接賦值:傳...
    Oliver_Li閱讀 274評(píng)論 0 0
  • title: Integer源碼分析date: 2017-09-11 15:07:46tags: javacate...
    zxcvbnmzsedr閱讀 451評(píng)論 0 1
  • Integer與原生類型轉(zhuǎn)換 Integer提供了幾個(gè)與原生類型轉(zhuǎn)換的方法: 由上面的源碼可知,Integer類型...
    alexwu59閱讀 412評(píng)論 0 0

友情鏈接更多精彩內(nèi)容