上次咱們已經對String
類源碼作了一個簡單的總結,感興趣的小夥伴能夠去看一下啃碎JDK源碼(一):String,今天來看看Java的Integer
包裝類。java
先來看看Integer
實現了哪些接口git
public final class Integer extends Number implements Comparable<Integer> {
能夠看到Integer
用final
修飾,表明不可被繼承,繼承Number
類實現Comparable
接口。面試
private final int value; public static final int MIN_VALUE = 0x80000000;//最大值 public static final int MAX_VALUE = 0x7fffffff;//最小值 public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
能夠看出使用了int
類型的value
來存儲值,而且定義了Integer
的最大值爲2^31-1
,最小值爲-2^31
。Integer
的基本數據類型爲int
。segmentfault
先來看一下Integer
的兩個構造函數:數組
public Integer(int value) { this.value = value; } public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
那麼這個parseInt
方法是幹啥用的呢?緩存
方法parseInt(String s,int radix)
的目的是輸出一個十進制數。less
好比:parseInt(1010,2)
意思就是:輸出2進制數1010在十進制下的數。ide
咱們平時用到Integer.parseInt("123");
其實默認是調用了int i =Integer.parseInt("123",10);
函數
下面是源碼:優化
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. */ if (s == null) { throw new NumberFormatException("null"); } //判斷基數是否在 2~36之間 if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); } if (radix > Character.MAX_RADIX) {//36 throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } int result = 0; boolean negative = false;//是否爲負數,默認爲false int i = 0, len = s.length(); int limit = -Integer.MAX_VALUE; int multmin; int digit; if (len > 0) { char firstChar = s.charAt(0); if (firstChar < '0') { // Possible leading "+" or "-" if (firstChar == '-') {//若是是負數,negative賦值爲true,限制變爲int的最小值 negative = true; limit = Integer.MIN_VALUE; } else if (firstChar != '+') throw NumberFormatException.forInputString(s); if (len == 1) // Cannot have lone "+" or "-" throw NumberFormatException.forInputString(s); i++; } /**multmin防止數據溢出 *若是是正數就是-2,147,483,64 *若是是負數就是-2,147,483,64 **/ multmin = limit / radix; while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE //獲取字符轉換成對應進制的整數 digit = Character.digit(s.charAt(i++),radix); if (digit < 0) { throw NumberFormatException.forInputString(s); } if (result < multmin) { throw NumberFormatException.forInputString(s); } result *= radix; if (result < limit + digit) { throw NumberFormatException.forInputString(s); } result -= digit; } } else { throw NumberFormatException.forInputString(s); } return negative ? result : -result; }
接下來來看一個比較經典的問題,看下面代碼:
Integer a = 100; Integer b = 100; Integer c = 200; Integer d = 200; System.out.println(a == b); System.out.println(c == d);
你認爲這裏是四個不一樣的對象,那麼輸出應該都是flase?
不,輸出結果爲:
true
false
經過javap -c/javap -verbose
命令能夠查看字節碼;紅色圈圈裏就是咱們jdk5以後的基本類型的自動包裝的字節碼實現,能夠看出,此處是調用了Integer.valueOf(..)
方法的:說白了就是Integer a = 100
等價於Integer a = Integer.valueOf(100)
JDK1.5以後,java提供了自動裝箱和自動拆箱的功能。自動裝箱也就是調用了Integer類的一個靜態方法valueOf
方法,那咱們來看看源碼是如何實現的:
看看IntegerCache
是個什麼東西:
能夠看到IntegerCache
是一個靜態內部類,low的值已經寫死-128,而high的值由你的虛擬機決定sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high")
,既然是一個參數也就意味着你能夠動態設置。而後在循環中將low - high
之間數字的裝箱後方法cache[]
這個Integer類型的數組中。這樣就完成了緩存。
由於當咱們調用valueOf
方法時傳入-128到127之間的數字時,Integer
會給咱們返回一樣的對象,記住這一點之後面試的時候也能夠和麪試官吹吹牛逼了!
接下來咱們來看看Integer
實現的equals
、hashcode
和toString
等方法:
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
能夠看到它會先判斷類型是否符合,而後進行拆箱比較操做。
看下hashcode
方法:
@Override public int hashCode() { return Integer.hashCode(value); } public static int hashCode(int value) { return value; }
能夠看到hashcode
直接返回自己的int值。
Integer
的toString
方法 是我認爲一個比較有趣的地方:
看下toString(int i)
源碼:
在上面用到了stringSize
方法,就是求這個Integer
數的長度,咱們來看看他是如何實現的:
能夠看到這段代碼在計算Integer
數長度時,構建了一個一維數組,而後拿x與數組每一個值進行比較。
還有一個getChars
方法是獲取數值對應的字符串,其中有兩個地方使用了很是巧妙的方式來進行除法運算和取餘運算。在計算機中,a/b
和 a%b
相比較位運算,都是比較費時的計算的。下面來看看jdk中是如何優化計算的:
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 while (i >= 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q << 6) + (q << 5) + (q << 2)); i = q; buf [--charPos] = DigitOnes[r]; buf [--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { q = (i * 52429) >>> (16+3); r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf [--charPos] = digits [r]; i = q; if (i == 0) break; } if (sign != 0) { buf [--charPos] = sign; } }
其中有一行代碼:
q = (i * 52429) >>> (16+3);
上面這行公式約等於 q * 0.1
,也就是說使用乘法計算比使用除法高效。
思路是這樣:
當 i >= 65536時,是每兩位取出數字,i /= 100,例如 i = 567235474,
(1)先取最後兩位 7 和 4 放入buf數組中,i = 5672354,buf = { , , , , , , , '7', '4'};
(2)再取最後兩位 5 和 4 放入buf數組中,i = 56723,buf = { , , , , , '5', '4', '7', '4'};
當 i < 65536 時,跳出循環,採用每一次取出一位數字,也就是 i /= 10
(3)取最後一位 3 放入buf數組中,i = 5672,buf = { , , , , '3', '5', '4', '7', '4'};
(4)取最後一位 2 放入buf數組中,i = 567,buf = { , , , '2', '3', '5', '4', '7', '4'};
(5)取最後一位 7 放入buf數組中,i = 56,buf = { , , '7', '2', '3', '5', '4', '7', '4'};
(6)取最後一位 6 放入buf數組中,i = 5,buf = { , '6', '7', '2', '3', '5', '4', '7', '4'};
(7)取最後一位 5 放入buf數組中,i = 0,buf = { '5', '6', '7', '2', '3', '5', '4', '7', '4'},結束。
關於Integer
類暫時介紹到這裏,有關其它的包裝類Long
等源碼部分也是相似的,後續就再也不介紹,有興趣的小夥伴能夠去研究一下。