給我一個(gè)可以看片的免費(fèi)seo排名官網(wǎng)
? ? 當(dāng)你掌握J(rèn)ava語言到了一定的階段,或者說已經(jīng)對(duì)Java的常用類和API都使用的行云流水。你會(huì)不會(huì)有一些思考?比如,這個(gè)類是如何設(shè)計(jì)的?這個(gè)方法是怎么實(shí)現(xiàn)的?接下來的一系列文章,我們一起學(xué)習(xí)下Java的一些常見類的源碼。本篇,一起分析下Integer的源碼。
目錄
一、兩道Integer的題目
二、Integer類圖
三、String轉(zhuǎn)int ? ?
1、Integer.parseInt
2、Integer.valueOf
四、總結(jié)?
一、兩道Integer的題目
? ? 可能有些同學(xué)java水平比較高,或者認(rèn)為自己沒必要去看Integer源碼。那你不妨看下接下來這幾道題目,看看你是否都能答對(duì)。? ?
1、如下代碼輸出什么?
public class IntegerTest1 {public static void main(String[] args) {Integer i1 = 100;Integer i2 = 100;Integer i3 = 200;Integer i4 = 200;System.out.println(i1 == i2);System.out.println(i3 == i4);}
}
答案是:true ? false
?2、如下代碼輸出什么?
public class IntegerTest {public static void main(String[] args) {String s = "10";System.out.println(Integer.getInteger(s));}
}
答案是:null(咦,為什么不是10?)
? ? 如果這兩道題目都答對(duì)了,那你可以叉掉這篇文章,因?yàn)槲乙膊幌肜速M(fèi)你的時(shí)間。如果你答錯(cuò)了,那么不妨一起學(xué)習(xí)下Integer的源碼?
二、Integer類圖
? ? 那么,接下來,我們一起看下Integer的源碼吧。Integer源碼不算短,1800+行代碼。其中有很多api是不常用的,因此,我們也僅去挑一些常用的api去看下其實(shí)現(xiàn)。如下是Integer及其關(guān)聯(lián)類/接口的類圖:
? ? 通過Integer類的類圖,我們總結(jié)下它的特點(diǎn):
- Integer類繼承自抽象類Number
- Integer類實(shí)現(xiàn)了Comparable接口
- Integer類使用final修飾,因此不可以有子類(不能被繼承)
三、String轉(zhuǎn)int ? ?
? ? 在日常工作中,我們經(jīng)常會(huì)將一個(gè)代表數(shù)字的String,轉(zhuǎn)為int,那么Java給我們提供了兩個(gè)方法:
1、Integer.parseInt
public static int parseInt(String s) throws NumberFormatException {return parseInt(s,10);}
? ? ?在使用這個(gè)方法的時(shí)候,我們需要注意trycatch一下NumberFormatException,否則當(dāng)輸入的String不是數(shù)字或者超過integer的范圍時(shí)會(huì)產(chǎn)生異常。
? ? 另外,該方法默認(rèn)是10進(jìn)制,當(dāng)然我們也可以調(diào)用兩個(gè)參數(shù)的方法傳入進(jìn)制去轉(zhuǎn)為其他進(jìn)制的int,但這不常用:
public static int parseInt(String s, int radix)throws NumberFormatException{...}
? ? 接下來,詳細(xì)看下該方法的實(shí)現(xiàn):
? ? 首先,會(huì)判斷傳入的String不為null,檢驗(yàn)傳入的進(jìn)制參數(shù)在范圍內(nèi)[2 , 36],而且會(huì)判斷字符串的長(zhǎng)度大于0,否則會(huì)拋出NumberFormatException:
if (s == null) {throw new NumberFormatException("null");}if (radix < Character.MIN_RADIX) {throw new NumberFormatException("radix " + radix +" less than Character.MIN_RADIX");}if (radix > Character.MAX_RADIX) {throw new NumberFormatException("radix " + radix +" greater than Character.MAX_RADIX");}if (len > 0) {...} else {throw NumberFormatException.forInputString(s);}
? ? ? 當(dāng)字符串滿足轉(zhuǎn)化為int的條件時(shí),就執(zhí)行將String轉(zhuǎn)為int的代碼(上述被...省略的代碼)。我們也分兩步來看:
? ? 首先,根據(jù)字符串的首字符判斷是正數(shù)、負(fù)數(shù)或是非法。
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++;}
(1)如果第一個(gè)字符是'-',會(huì)把表示正負(fù)數(shù)的negative置為true,同時(shí)把其limit置為Integer的最小值;
(2)如果不是'-'且如果不是'+',那說明是其他的字符,拋出異常;
(3)如果首字符是'+'或'-',但是長(zhǎng)度為1,說明是"+"或"-",也是非數(shù)字,拋出異常。
(4)如果首字符合法,那么i++,接下來看非符號(hào)的字符。
? ? 當(dāng)然,如果首字符不是符號(hào),而是數(shù)字,那么就直接走接下來的代碼:
int multmin = limit / radix;int result = 0;while (i < len) {// Accumulating negatively avoids surprises near MAX_VALUEint 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;
(1)遍歷字符串的字符,調(diào)用digit函數(shù),該函數(shù)在不能轉(zhuǎn)為數(shù)字時(shí)返回-1
(2)如果有字符不是數(shù)字(digit<0),那么拋出異常。
(3)如果沒問題,那就一步步計(jì)算轉(zhuǎn)為int,會(huì)判斷是否超過范圍,超過范圍則拋出異常
(4)最后,如果是負(fù)數(shù)返回result,如果是正數(shù),返回-result
? ? 在這里,可能有的同學(xué)沒看懂,為什么負(fù)數(shù)返回的是result,而正數(shù)返回的是-result。我們把字符串?dāng)?shù)字轉(zhuǎn)為十進(jìn)制的方法,比如把"1234"轉(zhuǎn)為十進(jìn)制,其實(shí)是這么來的:
((((1 ??10)+ 2)??10) + 3)??10 + 4
= ((12 ??10) + 3) ??10 + 4
= (120 + 3)??10 + 4
= ?123??10 + 4
= ?1230?+ 4
= ?1234
? ? 而方法里面其實(shí)是反過來實(shí)現(xiàn)的:
((((-1 ??10)-?2)??10) -?3)??10 -?4
= ((-12 ??10) -?3) ??10 -?4
= (-120 -?3)??10 -?4
= ?-123??10 -?4
= ?-1230 -?4
= ?-1234
? ? 所以,它用的不是正向累加法,而是負(fù)向累加法。其實(shí)代碼里面也有注釋(負(fù)向累加避免在最大值附近發(fā)生意外):
// Accumulating negatively avoids surprises near MAX_VALUE
2、Integer.valueOf
? ? 第二種方法就是Integer.valueOf,該方法最后還是調(diào)用的parseInt。注意其返回值是Integer,而不是int。不過,現(xiàn)在已經(jīng)不用unboxing了,可以直接使用int去接收返回值。
public static Integer valueOf(String s, int radix) throws NumberFormatException {return Integer.valueOf(parseInt(s,radix));}
? ? 接下來,看看valueOf的實(shí)現(xiàn):
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
? ? suprise來了,Integer.valueOf( int i)這個(gè)方法,出現(xiàn)了IntegerCache這個(gè)內(nèi)部類,而且會(huì)返回cache里的對(duì)象或者一個(gè)新的Integer對(duì)象。那么,IntegerCache是什么?
private static class IntegerCache {static final int low = -128;static final int high;static final Integer[] cache;static Integer[] archivedCache;private IntegerCache() {}static {int h = 127;String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");int size;if (integerCacheHighPropValue != null) {try {size = Integer.parseInt(integerCacheHighPropValue);size = Math.max(size, 127);h = Math.min(size, 2147483518);} catch (NumberFormatException var6) {}}high = h;VM.initializeFromArchive(Integer.IntegerCache.class);size = high - -128 + 1;if (archivedCache == null || size > archivedCache.length) {Integer[] c = new Integer[size];int j = -128;for(int k = 0; k < c.length; ++k) {c[k] = new Integer(j++);}archivedCache = c;}cache = archivedCache;assert high >= 127;}}
? ? 可以看出,Integer內(nèi)部維護(hù)了一個(gè)IntegerCache,范圍是[-128,127]。valueOf方法,如果數(shù)值在[-128,127]之間,便返回指向IntegerCache.cache中已經(jīng)存在的對(duì)象的引用;否則創(chuàng)建一個(gè)新的Integer對(duì)象。
? ? 這其實(shí)解答了我們的第一個(gè)問題。 在這里順便也看下我們的第二個(gè)問題,為什么Integer.getInteger("10")返回的是null,而不是10。其實(shí)調(diào)用的是System.getProperty,跟String轉(zhuǎn)int半毛錢關(guān)系沒有:
public static Integer getInteger(String nm, Integer val) {String v = null;try {v = System.getProperty(nm);} catch (IllegalArgumentException | NullPointerException e) {}if (v != null) {try {return Integer.decode(v);} catch (NumberFormatException e) {}}return val;}
四、總結(jié)?
? ? 其實(shí)Integer我們常用的無非就是這兩個(gè)String轉(zhuǎn)int的方法,Integer還提供了一些簡(jiǎn)單的計(jì)算方法例如max,min,sum,其實(shí)我們也用不到。還有intValue方法,從java1.6開始,我們也不需要拆箱(unboxing)了,所以也用不到。
? ? 本篇基于Integer的兩個(gè)常用方法,看了其關(guān)鍵代碼的實(shí)現(xiàn),也知道了其內(nèi)部維護(hù)著一個(gè)緩存。通過分析其源碼實(shí)現(xiàn),也解答了開篇拋出的兩個(gè)問題。