Integer的基本實現
Integer的使用
Integer封裝的操做
基本描述:
Integer是對原生基本類型int的封裝,其定義value來存儲值和一些用於描述int的信息java
int value;//int int SIZE = 32;//1位正負標識+31位數據 int BYTES = SIZE / Byte.SIZE;//所佔字節 int MIN_VALUE = 0x80000000;//最小值,32個1 int MAX_VALUE = 0x7fffffff;//最大值,0+31個1
構造函數:
容許經過String和int入參來爲value賦值,可是兩個構造函數都已棄用git
經過註釋能夠看到,推薦經過valueOf()的方法來返回一個Integer數組
/** * @deprecated * It is rarely appropriate to use this constructor. The static factory * {@link #valueOf(int)} is generally a better choice, as it is * likely to yield significantly better space and time performance. */ @Deprecated(since="9") public Integer(int value) { this.value = value; } /** * @deprecated * It is rarely appropriate to use this constructor. * Use {@link #parseInt(String)} to convert a string to a * {@code int} primitive, or use {@link #valueOf(String)} * to convert a string to an {@code Integer} object. */ @Deprecated(since="9") public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
使用推薦的方法獲取Integer實例和構造方法有何不一樣?app
//----------------------int入參------------------ @HotSpotIntrinsicCandidate public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } //----------------------String入參------------------ public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); } //radix表示進制,取值範圍爲[2, 36] public static Integer valueOf(String s, int radix) throws NumberFormatException { return Integer.valueOf(parseInt(s,radix)); }
若是入參中的int在IntegerCache內部類的Integer cache[]中存在則返回數組中的Integer不然經過構造函數建立(棄用的那個)jvm
經過parseInt(s,radix)方法解析字符串,返回int值
radix參數表示字符串轉換的int值的進制,其取值範圍爲[2,36]函數
解析IntegerCache和parseInt的實現this
IntegerCache
//The cache is initialized on first usage. 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; //The size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.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); } 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() {} }
IntegerCache是一個私有靜態內部類該類內部定義了一個數組Integer cache[],數組內的數據由-128起始,默認至127爲止(byte的範圍)spa
該數組的最大值可經過在jvm中設置
-XX:AutoBoxCacheMax=<size>來設置其大小code
數組cache[128]爲0,valueof(int)參數的值符合這個範圍都會直接從數組中返回Integerorm
有意思的是valueof(int)是@HotSpotIntrinsicCandidate的,關於它的描述是這樣的:
JDK的源碼中,被@HotSpotIntrinsicCandidate標註的方法,在HotSpot中都有一套高效的實現,該高效實現基於CPU指令,運行時,HotSpot維護的高效實現會替代JDK的源碼實現,從而得到更高的效率。
估計這就是推薦使用的主要緣由吧!
parseInt
public static int parseInt(String s, int radix) throws NumberFormatException { ... boolean negative = false;//正負標識 int i = 0, len = s.length(); int limit = -Integer.MAX_VALUE; if (len > 0) { char firstChar = s.charAt(0); //判斷輸入的字符串是否爲"-"開頭 if (firstChar < '0') { // Possible leading "+" or "-" if (firstChar == '-') { 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++; } //轉化邏輯 int multmin = limit / radix; int result = 0; while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE int digit = Character.digit(s.charAt(i++), radix); if (digit < 0 || result < multmin) { throw NumberFormatException.forInputString(s); } result *= radix; if (result < limit + digit) { throw NumberFormatException.forInputString(s); } result -= digit; } return negative ? result : -result; } else { throw NumberFormatException.forInputString(s); } } static final 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' };
字符串轉化爲int的關鍵在於digits數組,以16進製爲例,用0...9,a...f表示0到15,滿16纔會進1。也就是超過10進制之後,大於10的數要使用a開始的字母表示,可是字母只有26個,進制又必須從2開始,故進制的取值範圍也就定義爲[2, 36]
故入參的字符串s也必須符合digits數組中的元素以及額外的只可能存在第一位"+"或者"-"
parseInt的轉化邏輯爲:
在每次循環中
而後返回結果,經過:
return negative ? result : -result;
int a = 5; Integer w = 6; Integer test = Integer.valueOf(w); int testP = Integer.valueOf(a);
轉化成對應的字節碼,則
0: iconst_5
1: istore_1
直接將天然數壓棧
調用Integer的靜態方法valueof(6)獲得Integer實例
獲取操做數棧中w的引用,調用intValue返回int值,再經過valueof獲取Integer實例
獲取操做數棧中的a,調用valueof獲取Integer實例,再經過intValue返回int值
由此可知,對於基本類型的封裝類,編譯器會自動調用其一些方法來實現用戶操做的簡化!
Object虛函數的實現
父類Number的虛函數實現
字節操做
Object虛函數的實現
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; } public static int hashCode(int value) { return value; } public static String toString(int i) { int size = stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; StringUTF16.getChars(i, size, buf); return new String(buf, UTF16); } }
經過Integer的intValue獲取入參的Integer封裝的int值並與value進行==尋址判斷
hashCode返回的就是一個int值,故直接使用value自己
使用char數組作中轉,經過String實例化一個String實例
根據是否開啓壓縮機制判斷使用的是LATIN1仍是UTF16
父類Number的虛函數實現
public byte byteValue() { return (byte)value; } public double doubleValue() { return (double)value; } public float floatValue() { return (float)value; } public int intValue() { return value; } public long longValue() { return (long)value; } public short shortValue() { return (short)value; }
只是對value進行強轉
字節操做
計算int二進制形式左(右)側有幾個0,遇到1就中止計數
計算int二進制形式1的數量
左(右)移二進制形式
按位(字節)置換
計算int二進制形式左(右)側有幾個0,遇到1就中止計數
//左側 public static int numberOfLeadingZeros(int i) { // HD, Count leading 0's if (i <= 0) return i == 0 ? 32 : 0; int n = 31; if (i >= 1 << 16) { n -= 16; i >>>= 16; } if (i >= 1 << 8) { n -= 8; i >>>= 8; } if (i >= 1 << 4) { n -= 4; i >>>= 4; } if (i >= 1 << 2) { n -= 2; i >>>= 2; } return n - (i >>> 1); } //右側 public static int numberOfTrailingZeros(int i) { // HD, Figure 5-14 int y; if (i == 0) return 32; int n = 31; y = i <<16; if (y != 0) { n = n -16; i = y; } y = i << 8; if (y != 0) { n = n - 8; i = y; } y = i << 4; if (y != 0) { n = n - 4; i = y; } y = i << 2; if (y != 0) { n = n - 2; i = y; } return n - ((i << 1) >>> 31); }
1 負數1標識,左側無0,0全爲0,直接返回32(int爲32位)
2 經過1 << 16判斷,判斷條件爲是否比它大,左邊16位是否全爲0,決定接下來操做左或右半邊
3 再經過i << 8,4,2,1折半再折半計算出不爲0的數字的位置,從而得出0的數量
經過i <<16,不爲0則右邊有1,再i << 8,4,2,1,判斷出右邊數起的第一個1,從而計算出0的數量
計算int二進制形式1的數量
public static int bitCount(int i) { // HD, Figure 5-2 i = i - ((i >>> 1) & 0x55555555); i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); i = (i + (i >>> 4)) & 0x0f0f0f0f; i = i + (i >>> 8); i = i + (i >>> 16); return i & 0x3f; }
0x3 = 0011,經過作&運算記錄後兩位的數據狀況
0x0f = 0000 1111,經過作&運算記錄後四位的數據狀況
先作>>>右移一位再與01作&運算,記錄了兩位二進制左邊數字的1的數量,再用原來的二進制數減去記錄的值
如11:11-01=10(11有兩個1)
2 通過第一步計算,記錄了以兩位數爲單位的1的數量
把第一步的結果與0011作&運算獲得四位二進制結果的後兩位計算,0011再與四位二進制結果>>>右移兩位計算前兩位的結果,再把其相加獲得四位數中1的數量
如1011
1011 - 0101 = 0110
0001 + 0010 = 0011(1011有三個1)
3 i + (i >>> 4),i + (i >>> 8),i + (i >>> 16)分別把獲得的上一步計算的結果整合計算
計算完成後記錄結果的有效位數只有右邊八位,32位數一共最多32個1,因此實際的有效位數只有右邊6位
左(右)移二進制形式
public static int rotateLeft(int i, int distance) { return (i << distance) | (i >>> -distance); } public static int rotateRight(int i, int distance) { return (i >>> distance) | (i << -distance); }
調用<<或>>運算符移動,同時經過 | >>> -distance獲得移動消逝的數據,並將其放在補0的位置
-distance表示移動-distance負數的表現形式int截取5位,long截取6位,如-1爲32個1,截取5位爲1 1111,爲31,也就是不算位移,移動的「路程」是32,正好把移出的數據再補回補0的地方
按位(字節)置換
public static int reverseBytes(int i) { return (i << 24) | ((i & 0xff00) << 8) | ((i >>> 8) & 0xff00) | (i >>> 24); } public static int reverse(int i) { // HD, Figure 7-1 i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555; i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333; i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f; return reverseBytes(i); }
i << 24與i >>> 24作 | 運算獲得最左右兩邊的置換
0xff00二進制形式爲1111 1111 0000 0000
正好用來處理中間左八位和右八位的交換,主要是&和移動的前後來實現不一樣的位的清零
1 使用01來記錄兩位二進制中的一位,再經過移動記錄另外一位,作 | 運算的會把兩位的二進制數交換位置
2 經過0011來交換四位中的前兩位和後兩位
3 經過0000 1111來交換前四位和後四位
4 經過前三步實現交換每8位的循序,再經過按字節置換交換所有的順序
Integer中還有關於
static final byte[] 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', } ; static final byte[] 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', } ;
這兩個數組的應用和字符和byte之間轉換的精彩實現,有時間會記錄。