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;}