输入一个表示整数的字符串,把该字符串转换成整数并输出。 例如输入字符串"345",则输出整数 345。
这个面试题不太 涉及算法和数据结构,主要考察你的编程习惯,有没有意识去做一些验证,对输入的校验。小问题验证大方面。乘机我们来看看java api中对这个问题的处理
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,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");
}
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;
}
先了解下面的知识,对理解上面的代码有好处。
在Java中>、>>、>>>三者的区别
在java中:
>表示大于,如:if(a>b)...结果是boolean类型
>>表示右移,如:int i=15; i>>2的结果是3,移出的部分将被抛弃。
转为二进制的形式可能更好理解,0000 1111(15)右移2位的结果是0000 0011(3),0001 1010(18)右移3位的结果是0000 0011(3)。
j>>>i 与 j/(int)(Math.pow(2,i))的结果相同,其中i和j是整形。
我们一步一步的debug, 来看看处理代码
public static void main(String[] args){
//10进制
Integer.parseInt("235",10);
}
上面是入口函数。
传入的字符串为"235"。进入方法体后,第一步是判断是否为null。如果为空,抛出异常。然后是判断基数是否在可允许范围内[2-32],我们传入的是10。在可允许内
result:我们需要的结果
negative:是否为负数。默认为false
i:游标,指向字符串当前的索引,遍历字符串中字符。
len:字符串大小
limit:整形的最大值的负值。比整形的最小值-2147483648大1.
multmin:
digit:保存字符经过转化后的整形值
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,如果为1,不符合要求,因为只有符号位肯定是不复制整数的定义的。
最后字符串遍历的游标自增1。表示遍历要从第二个字符开始,因为第一个字符我们已经判断是符号位。
首先我们将multmin的值赋上值,赋上值有啥作用?,它为啥要除以基准值。暂时还不清楚。先放着吧。
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;
}
digit = Character.digit(s.charAt(i++),radix);
可以看见字符'2'的ascii码为50,我们对照一下的确是50。
上面的方法中,首先将字符转换成ascii码,然后再调用覆盖函数digit。
这个时候会发现传进来的是50,也就是‘2’的ascii码值。进入该函数后,首先通过CharacterData.of方法来得到该字符属于哪个编码集范围内。
static final CharacterData of(int ch) {
if (ch >>> 8 == 0) { // fast-path
return CharacterDataLatin1.instance;
} else {
switch(ch >>> 16) { //plane 00-16
case(0):
return CharacterData00.instance;
case(1):
return CharacterData01.instance;
case(2):
return CharacterData02.instance;
case(14):
return CharacterData0E.instance;
case(15): // Private Use
case(16): // Private Use
return CharacterDataPrivateUse.instance;
default:
return CharacterDataUndefined.instance;
}
}
}
进入CharacterDataLatin1类的digit方法
int digit(int ch, int radix) {
int value = -1;
if (radix >= Character.MIN_RADIX && radix <= Character.MAX_RADIX) {
int val = getProperties(ch);
int kind = val & 0x1F;
if (kind == Character.DECIMAL_DIGIT_NUMBER) {
value = ch + ((val & 0x3E0) >> 5) & 0x1F;
}
else if ((val & 0xC00) == 0x00000C00) {
// Java supradecimal digit
value = (ch + ((val & 0x3E0) >> 5) & 0x1F) + 10;
}
}
return (value < radix) ? value : -1;
}
int getProperties(int ch) {
char offset = (char)ch;
int props = A[offset];
return props;
}
为何要做位与运算,先来看看位于运算是什么?
& 是按二进制的按位与,即 1 & 1 = 1 1 & 0 = 0 3 & 1 → 11(二进制) & 1 = 1
10进制数402667017转化为二进制数为
11000000000000011011000001001
if (kind == Character.DECIMAL_DIGIT_NUMBER)
value = ch + ((val & 0x3E0) >> 5) & 0x1F;
0x3E0 = 10 1111 0000 &10 0000 1001 = 10 0000 0000 然后向右位移5位得到10 000由于优先级+大于&。所以先进行相加运算50+16 = 66 (1000010)
1000010&11111 = 10 =,10进制就为2;所以最后的value = 2;
所以方法返回到Integer.parseInt中,得到digit = 2;
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;
}
后面一个判断result