摘要:估計這就是推薦使用的主要原因吧正負標識判斷輸入的字符串是否為開頭轉(zhuǎn)化邏輯字符串轉(zhuǎn)化為的關(guān)鍵在于數(shù)組,以進制為例,用表示到,滿才會進。
Integer的基本實現(xiàn)Integer的基本實現(xiàn)
Integer的使用
Integer封裝的操作
基本描述:
Integer是對原生基本類型int的封裝,其定義value來存儲值和一些用于描述int的信息
int value;//int int SIZE = 32;//1位正負標識+31位數(shù)據(jù) int BYTES = SIZE / Byte.SIZE;//所占字節(jié) int MIN_VALUE = 0x80000000;//最小值,32個1 int MAX_VALUE = 0x7fffffff;//最大值,0+31個1
構(gòu)造函數(shù):
允許通過String和int入?yún)頌関alue賦值,但是兩個構(gòu)造函數(shù)都已棄用
通過注釋可以看到,推薦通過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實例和構(gòu)造方法有何不同?
//----------------------int入?yún)?----------------- @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入?yún)?----------------- 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入?yún)?/p>
如果入?yún)⒅械膇nt在IntegerCache內(nèi)部類的Integer cache[]中存在則返回數(shù)組中的Integer否則通過構(gòu)造函數(shù)創(chuàng)建(棄用的那個)
String入?yún)?/p>
通過parseInt(s,radix)方法解析字符串,返回int值
radix參數(shù)表示字符串轉(zhuǎn)換的int值的進制,其取值范圍為[2,36]
解析IntegerCache和parseInt的實現(xiàn)
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=} 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是一個私有靜態(tài)內(nèi)部類該類內(nèi)部定義了一個數(shù)組Integer cache[],數(shù)組內(nèi)的數(shù)據(jù)由-128起始,默認至127為止(byte的范圍)
該數(shù)組的最大值可通過在jvm中設(shè)置
-XX:AutoBoxCacheMax=
數(shù)組cache[128]為0,valueof(int)參數(shù)的值符合這個范圍都會直接從數(shù)組中返回Integer
有意思的是valueof(int)是@HotSpotIntrinsicCandidate的,關(guān)于它的描述是這樣的:
JDK的源碼中,被@HotSpotIntrinsicCandidate標注的方法,在HotSpot中都有一套高效的實現(xiàn),該高效實現(xiàn)基于CPU指令,運行時,HotSpot維護的高效實現(xiàn)會替代JDK的源碼實現(xiàn),從而獲得更高的效率。
估計這就是推薦使用的主要原因吧!
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++; } //轉(zhuǎn)化邏輯 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" };
字符串轉(zhuǎn)化為int的關(guān)鍵在于digits數(shù)組,以16進制為例,用0...9,a...f表示0到15,滿16才會進1。也就是超過10進制以后,大于10的數(shù)要使用a開始的字母表示,但是字母只有26個,進制又必須從2開始,故進制的取值范圍也就定義為[2, 36]
故入?yún)⒌淖址畇也必須符合digits數(shù)組中的元素以及額外的只可能存在第一位"+"或者"-"
parseInt的轉(zhuǎn)化邏輯為:
在每次循環(huán)中
取出digit,確定進制后轉(zhuǎn)化的int數(shù)
通過result *= radix;把上一次循環(huán)的數(shù)據(jù)進一位
通過result -= digit;把當前的數(shù)據(jù)加入result
然后返回結(jié)果,通過:
return negative ? result : -result;
int a = 5; Integer w = 6; Integer test = Integer.valueOf(w); int testP = Integer.valueOf(a);
轉(zhuǎn)化成對應(yīng)的字節(jié)碼,則
int a = 5
0: iconst_5
1: istore_1
直接將自然數(shù)壓棧
Integer w = 6
2: bipush 6
4: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
7: astore_2
調(diào)用Integer的靜態(tài)方法valueof(6)得到Integer實例
Integer test = Integer.valueOf(w)
8: aload_2
9: invokevirtual #3 // Method java/lang/Integer.intValue:()I
12: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
15: astore_3
獲取操作數(shù)棧中w的引用,調(diào)用intValue返回int值,再通過valueof獲取Integer實例
int testP = Integer.valueOf(a)
16: iload_1
17: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
20: invokevirtual #3 // Method java/lang/Integer.intValue:()I
獲取操作數(shù)棧中的a,調(diào)用valueof獲取Integer實例,再通過intValue返回int值
由此可知,對于基本類型的封裝類,編譯器會自動調(diào)用其一些方法來實現(xiàn)用戶操作的簡化!
Integer封裝的操作Object虛函數(shù)的實現(xiàn)
父類Number的虛函數(shù)實現(xiàn)
字節(jié)操作
Object虛函數(shù)的實現(xiàn)
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); } }
equals
通過Integer的intValue獲取入?yún)⒌腎nteger封裝的int值并與value進行==尋址判斷
hashCode
hashCode返回的就是一個int值,故直接使用value本身
toString
使用char數(shù)組做中轉(zhuǎn),通過String實例化一個String實例
根據(jù)是否開啟壓縮機制判斷使用的是LATIN1還是UTF16
父類Number的虛函數(shù)實現(xiàn)
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進行強轉(zhuǎn)
字節(jié)操作
計算int二進制形式左(右)側(cè)有幾個0,遇到1就停止計數(shù)
計算int二進制形式1的數(shù)量
左(右)移二進制形式
按位(字節(jié))置換
計算int二進制形式左(右)側(cè)有幾個0,遇到1就停止計數(shù)
//左側(cè) 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); } //右側(cè) 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); }
左側(cè):numberOfLeadingZeros
1 負數(shù)1標識,左側(cè)無0,0全為0,直接返回32(int為32位)
2 通過1 << 16判斷,判斷條件為是否比它大,左邊16位是否全為0,決定接下來操作左或右半邊
3 再通過i << 8,4,2,1折半再折半計算出不為0的數(shù)字的位置,從而得出0的數(shù)量
右側(cè):numberOfTrailingZeros
通過i <<16,不為0則右邊有1,再i << 8,4,2,1,判斷出右邊數(shù)起的第一個1,從而計算出0的數(shù)量
計算int二進制形式1的數(shù)量
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; }
0x5 = 0101,通過做&運算記錄雙數(shù)位的數(shù)據(jù)情況
0x3 = 0011,通過做&運算記錄后兩位的數(shù)據(jù)情況
0x0f = 0000 1111,通過做&運算記錄后四位的數(shù)據(jù)情況
1 int的二進制形式的可能有 00,01,10,11
先做>>>右移一位再與01做&運算,記錄了兩位二進制左邊數(shù)字的1的數(shù)量,再用原來的二進制數(shù)減去記錄的值
如11:11-01=10(11有兩個1)
2 經(jīng)過第一步計算,記錄了以兩位數(shù)為單位的1的數(shù)量
把第一步的結(jié)果與0011做&運算得到四位二進制結(jié)果的后兩位計算,0011再與四位二進制結(jié)果>>>右移兩位計算前兩位的結(jié)果,再把其相加得到四位數(shù)中1的數(shù)量
如1011
1011 - 0101 = 0110
0001 + 0010 = 0011(1011有三個1)
3 i + (i >>> 4),i + (i >>> 8),i + (i >>> 16)分別把得到的上一步計算的結(jié)果整合計算
計算完成后記錄結(jié)果的有效位數(shù)只有右邊八位,32位數(shù)一共最多32個1,所以實際的有效位數(shù)只有右邊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); }
移動
調(diào)用<<或>>運算符移動,同時通過 | >>> -distance得到移動消逝的數(shù)據(jù),并將其放在補0的位置
-distance表示移動-distance負數(shù)的表現(xiàn)形式int截取5位,long截取6位,如-1為32個1,截取5位為1 1111,為31,也就是不算位移,移動的“路程”是32,正好把移出的數(shù)據(jù)再補回補0的地方
按位(字節(jié))置換
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); }
按字節(jié)置換:reverseBytes
i << 24與i >>> 24做 | 運算得到最左右兩邊的置換
0xff00二進制形式為1111 1111 0000 0000
正好用來處理中間左八位和右八位的交換,主要是&和移動的先后來實現(xiàn)不同的位的清零
按位置換:reverse
1 使用01來記錄兩位二進制中的一位,再通過移動記錄另一位,做 | 運算的會把兩位的二進制數(shù)交換位置
2 通過0011來交換四位中的前兩位和后兩位
3 通過0000 1111來交換前四位和后四位
4 通過前三步實現(xiàn)交換每8位的循序,再通過按字節(jié)置換交換全部的順序
Integer中還有關(guān)于
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", } ;
這兩個數(shù)組的應(yīng)用和字符和byte之間轉(zhuǎn)換的精彩實現(xiàn),有時間會記錄。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74526.html
摘要:作為條件變量的的不僅可以認為內(nèi)嵌了一把鎖,還內(nèi)嵌了一個條件變量。操作條件變量的函數(shù)將當前線程在條件變量上阻塞,一般是為了等待其他線程的某件事情執(zhí)行完成。其它裝箱類其它裝箱類的代碼這里就不分析了。重點關(guān)注下各裝箱類的緩存范圍。 jdk源碼讀到現(xiàn)在這里,重要的集合類也讀了一部分了。集合類再往下讀的話,就要涉及到兩個方向。第一,是比較典型的但是不常用的數(shù)據(jù)結(jié)構(gòu),這部分我準備將數(shù)據(jù)結(jié)構(gòu)復(fù)習(xí)、回...
摘要:最近計劃把手冊,認真的先過一遍。語言參考類型新認知強制轉(zhuǎn)換類型用。后期靜態(tài)綁定從這里開始語言參考生成器新認知生成器汗水的核心是關(guān)鍵字。語言參考預(yù)定義變量超全局變量前一個錯誤信息原始數(shù)據(jù)以上 showImg(https://segmentfault.com/img/remote/1460000010147451); 最近計劃把 PHP手冊,認真的先過一遍。記錄一些以前不知道,不明確的知識...
摘要:而且,與是一對多關(guān)系一個分類下有很多,一個只能歸屬于一個與是一對多關(guān)系一篇博客下有很多,一條只能歸屬于一篇與是多對多關(guān)系一篇有很多,一個下有很多。 說明:本文主要聊一聊Laravel測試數(shù)據(jù)填充器Seeder的小技巧,同時介紹下Laravel開發(fā)插件三件套,這三個插件挺好用哦。同時,作者會將開發(fā)過程中的一些截圖和代碼黏上去,提高閱讀效率。 備注:在設(shè)計個人博客軟件時,總會碰到有分類Ca...
摘要:加載因子是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數(shù)超出了加載因子與當前容量的乘積時,則要對該哈希表進行操作即重建內(nèi)部數(shù)據(jù)結(jié)構(gòu),從而哈希表將具有大約兩倍的桶數(shù)。成員變量每個對由封裝,存在了對象數(shù)組中。 雖是讀書筆記,但是如轉(zhuǎn)載請注明出處 http://segmentfault.com/blog/exploring/ .. 拒絕伸手復(fù)制黨 LinkedLis...
摘要:那么,如果之后不是簡單的操作,而是還有其它業(yè)務(wù)操作,之后才是,比如下面這樣,這該怎么辦呢其它業(yè)務(wù)操作這時候就沒辦法使用提供的方法了,只能業(yè)務(wù)自己來保證線程安全了,比如下面這樣其它業(yè)務(wù)操作這樣雖然不太友好,但是最起碼能保證業(yè)務(wù)邏輯是正確的。 刪除元素 刪除元素跟添加元素一樣,都是先找到元素所在的桶,然后采用分段鎖的思想鎖住整個桶,再進行操作。 public V remove(Objec...
閱讀 2038·2021-11-23 10:08
閱讀 2371·2021-11-22 15:25
閱讀 3308·2021-11-11 16:55
閱讀 806·2021-11-04 16:05
閱讀 2684·2021-09-10 10:51
閱讀 735·2019-08-29 15:38
閱讀 1614·2019-08-29 14:11
閱讀 3514·2019-08-29 12:42