Integer的parseInt方法也是比較常用的方法,我們同樣重點來研究一下。看到源碼我們發現有兩個parseInt方法:
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");
}
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");
}
int result = 0;
boolean negative = 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;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
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;
}
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
可以看到,第二個方法只是調用了第一個方法,所以只要研究第一個parseInt即可。
第一個參數是要轉換的字符串,第二個參數是進制數。
一開始先進行幾個判斷,s不能爲空,進制數必須在2到36之間,如果不滿足則拋出異常。
下面的處理都是基於負數,因爲負數Integer.MIN_VALUE
的絕對值比較大,而且全部基於負數處理在算法上比較統一。
接下來先取第一個字符,是數字還是正負號分別進行處理。
while循環中的代碼是核心處理邏輯,也就是把字符串轉換成數字。
我們先想一下,考慮一個三位數123,比較通常的算法是:
如果是十進制,123=110的2次方+210的1次方+310的0次方。
如果是八進制,123=18的2次方+28的1次方+38的0次方。
但仔細看while循環中的這兩行代碼,result *= radix;
和result -= digit;
,我們發現他並不是使用上面的算法,而是使用了變種的算法:
如果是十進制,123=((1*10+2)10+3)。
如果是八進制,123=((18+2)*8+3)。
意思其實是一樣的,但是這種算法對於程序設計來說更加友好。
至於爲什麼是result -= digit;
而不是result += digit;
,是因爲這裏的計算全部基於負數,所以算法裏的加在這裏就是減。
我們還注意到,代碼裏定義了一個int multmin;
,以及下面還有這行代碼:multmin = limit / radix;
,以及循環裏的if (result < multmin)
, if (result < limit + digit)
,這又是幹什麼呢?
這是該方法的另一個精妙之處,它用來判斷是否溢出。每一次的循環都會判斷下一次循環的計算是否會溢出。
爲了便於理解,我們以十進制爲例,並且假設十進制的最大值爲998,
那麼定義的limit就是-998,根據multmin = limit / radix;
這行代碼,multmin就是-99。
進入循環以後,假如result已經到了-100,if (result < multmin)
會check出來,因爲在下一次循環的時候,result=-10010=-1000,溢出。
假如result爲-99,if (result < multmin)
可以通過,但是如果digit=9,那麼if (result < limit + digit)
會check出來,因爲在下一次循環的時候,result=-9910-9=-999,溢出。