public static int parseInt(String s, int radix) throws Exception
{
/** 对字符串判空,注意这里并不是没有判断空内容(长度为0的空串),下面判断了 */
if (s == null)
{
throw new RuntimeException();
}
/** Character.MIN_RADIX这个是java字符支持的最小进制编码 */
/** Character.MIN_RADIX = 2 */
if (radix < Character.MIN_RADIX)
{
throw new RuntimeException();
}
/** Character.MAX_RADIX这个是java字符支持的最大进制编码 */
/** Character.MIN_RADIX = 36 */
/** 涨知识了,java支持的最大字符编码进制是36 */
if (radix > Character.MAX_RADIX)
{
throw new RuntimeException();
}
/** 一堆局部变量,用到的时候解释具体含义 */
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
/** 这里注意和这个limit变量的初始化值,下文需要去对比*/
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
/** 这里是对字符串长度的判断,回顾方法开始时的提示*/
if (len > 0)
{
/** 得到首位字符 */
/** 小细节,本方法中去对比字符串中的字符的时候全部采用的charAt方法 */
/** 并没有将字符串转换成char数组,哈哈,省去了一个数组长度的空间消耗 */
/** 但是,同时需要每次去调用一次charAt方法,(String内部是有对应的char数组的) */
char firstChar = s.charAt(0);
/** 判断是否是非法字符,注意这里默认首位"+-"号都不算非法字符 */
if (firstChar < '0')
{
/** 首位是负号 */
if (firstChar == '-')
{
/** negative在这里被置为了true,本身又是boolean值 */
/** 所以,很明显,negative是一个标识位 */
/** 标识的内容就是,当前字符串首位是否是负号 */
negative = true;
/** limit变量在首位是负号的时候,被置为了int类型范围内的最小值 */
limit = Integer.MIN_VALUE;
}
else if (firstChar != '+')
{
/** ASCII码小于字符‘0’的情况下,不是负号,又不是正号,那就是非法字符 */
/** java中字符是有数值的,其数值对应ASCII中的值 */
throw new RuntimeException();
}
/** 如果上述没有抛出异常,证明首位一定是符号字符 */
/** 首位符号字符的情况下,长度自然不能为1,显然一个数值不能只有一个符号 */
if (len == 1)
{
throw new RuntimeException();
}
/** 当正确执行到这里的时候,表明首位是符号位且符号位后续还有字符,i++ */
/** i就是对当前字符串的字符位置的索引值,此时的i表明之后的操作从第二个字符开始 */
/** 因为第一个字符已经处理完了(符号位) */
i++;
}
/** radix是一个int值,数值内容代表当前数值是什么进制的编码 */
/** radix=10,表明使用的编码进制是我们最常用的十进制编码 */
/** 这条语句的含义就是把limit右移一位(无论是多少进制的编码) */
/** 例如,十进制编码下limit = 123456;那limit/radix = 12345 */
/** 记录一个这样的值,有什么意义,下文会理解 */
multmin = limit / radix;
/** 索引从左至右以此遍历字符串中的每一个字符 */
while (i < len)
{
/** Character.digit(char a,int b):该方法是把a字符转换成对应b进制的数值 */
/** 例如:Character.digit('1',10):结果就是数值1(十进制) */
/** 注意此时的radix是10进制(我们以十进制调用该方法为例) */
digit = Character.digit(s.charAt(i++),radix);
/** 字符小于0,结束,证明其是非法字符 */
if (digit < 0)
{
throw new RuntimeException();
}
/** 这条语句先不看,等分析下面的语句后,才能明白这里的作用
*
* 这条语句在字符串的长度超过int值最大可接受长度的时候会拦截
*
* 比如字符串 21474836470 比Integer.MAX_VALUE的最大值还多出一位
*
* 这条语句就是解决了上述这个字符串的拦截
* 当已经执行到int所能承受的最大长度位数的时候,result - digit = -2147483647
* 这个值已经小于 multmin(multmin就是把limit右移一位)
* 所以之后雨果超过了这个长度,也就标识长度超过范围了已经
* 很有意思的一个设计点
*
**/
if (result < multmin)
{
throw new RuntimeException();
}
/** 这里是当前result左移一位,最后一位补0 */
result *= radix;
/** result < limit + digit 这样写不好直接理解 */
/** 我们转换成 result - dight < limit
* 注意这次变换在编码是错误的,也就是代码必须写成第一种形式
* 因为第二种形式的 result - dight 是可能会越界的
* 第二种形式的转换只是为了帮助理解
*
* 一步一步分析啊:
* ① 首先,limit在当前字符首位负号的时候是Integer.MIN_VALUE,
* 正号的时候是 -Integer.MAX_VALUE
* ② result是字符串从非符号位开始到当前索引的截取值
* ③ 这一条语句只有在被验证字符串恰好是int范围边界的时候才有用
*
* 举例子说明:Integer.MAX_VALUE = 2147483647 (一共10位)
* 假如我们的字符串是:s = "2147483648",一共10位
* 当前 i=10
* 那么此时的 result = -2147483640;digit = 8;
* 那么 result - digit = -2147483648 < limit
*
* limit 在字符串是正数的时候是,- Integer.MAX_VALUE = -2147483647;
* 这就表示字符串越界了(超过范围了,如果是负数,逻辑一致)
*
* */
if (result < limit + digit)
{
throw new RuntimeException();
}
/** 这条语句其实是配合上面的 result *= radix 这条语句一起发挥作用的 */
/** 其目的就是获得字符串中 前i个字符所形成的数值(符号位除外) */
result -= digit;
}
}
else
{
throw new RuntimeException();
}
/** negative就是字符串首位是否是负号的标识,这里就用上了 */
/** 因为整个代码逻辑全部是以转换负数,按照字符串从左到右遍历字符,然后迭代循环递减并与最大承受范围对比的一个过程 */
/** 其实也完全可以全部在正数逻辑上处理,之所以选择以负数处理,其实就是因为最小负数的绝对值比正数大1 */
/** 也就是Integer.MIN_VALUE取不到相反数,已经越界了,哈哈 */
return negative ? result : -result;
}