【Java源码分析】Integer源码分析
程序员文章站
2022-07-14 16:14:47
...
今天带来的是Integer源码的分析。代码已经注释的非常清晰了。
1.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.
*/
//String转换为Integter,不能是null
if (s == null) {
throw new NumberFormatException("null");
}
//最小二进制,最大36进制
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; //如果是正数negative = false,如果是负数negative = true
int i = 0, len = s.length(); //i是遍历String的下标,len是长度
int limit = -Integer.MAX_VALUE; //限制,不能超过Integer的最大值。负的MAX_VALUE(以下都是再负数范围内进行判断的,为了统一处理,因为正数的最大值转化为负数不会溢出,而负数的最小值转换为正数会溢出,我这里所说的溢出是指的Integer范围内)
int multmin; //一个限制,后面讲
int digit; //每个字符转换为数字后的值
//如果是非空字符串
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"//ASCII码表小于‘0’的都是字符
if (firstChar == '-') { //如果是负号
negative = true; //标志改为负号
limit = Integer.MIN_VALUE; //界限是Integer最小值
} else if (firstChar != '+') //如果不是加号,说明第一个符号是个非法字符,抛出异常
throw NumberFormatException.forInputString(s);
if (len == 1) // 不能只有一个 "+" 或者 "-"
throw NumberFormatException.forInputString(s);
i++; //i指向第一个数字的位置
}
//下面就是转换成数字的逻辑了。
/*有很多小伙伴到这里可能不是很懂。首先limit表示溢出边界范围(这个程序中,无论正负,都统一成了负数),radix表示进制。
举个例子:假设十进制,我们到77就代表溢出了,那么multmin = -77 / 10 = -7,为什么要算这个数,是为了后面的操作。*/
//这里可以用移位操作吧?
multmin = limit / radix;
while (i < len) { //i没越界,执行字符转换成数字
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix); //字符转换成数字
if (digit < 0) { //转换出来如果每一位是负数,抛出异常
throw NumberFormatException.forInputString(s);
}
//关键来了:当前结果是否小于multmin,如果小于,抛出溢出异常。注意multmin一直是负数,如果result比multmin还要小,说明执行 result *= radix 的时候肯定是溢出了(以咱们的例子继续,multmin为-7,result < multmin,假设result为-9,那么执行result *= radix,result变成了-90,就发生了溢出 ),如果不提前抛出异常,那么我们的result中存的是溢出后的结果(结果不准确了)
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
//这里又是一个溢出判断,注意:digit是非负数,result,limit是负数。
//换成result - digit < limit你可能更好理解,继续我们的例子,假设result = -70,digit = 9, -70 - 9 =- 79, 是小于-77的,这就发生了溢出。
//但是为什么不换成result - digit < limit呢,因为在这里,做减法可能发生溢出。当我们算出-79的时候,result就已经发生了溢出,所以就将表达式变换了一下result < limit + digit,防止了溢出
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit; //在没有溢出的情况下,算出result
}
//如果字符串是空串,直接抛出异常
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result; //判断标志,如果是负数,返回result,如果是正数,返回-result
}
2.IntegerCache内部类
/**
* Integer默认缓存-128到127之间的数,缓存在第一次使用时初始化。缓存的大小是可控制的,在server模式下用-XX:AutoBoxCacheMax=<size>
*/
private static class IntegerCache {
static final int low = -128; //注意,这个值自始至终没有变过,所以下限一直是-128
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //high的值可以从配置文件中读取
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1); //注意,这里刚开始看可能很突兀,为什么是Integer.MAX_VALUE - (-low) -1呢?因为创建的是一个在low到high范围的Integer数组,如果大于了这个值,那么在为数组分配空间的时候就溢出了
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1]; //缓存的最大空间是Integer.MAX_VALUE,这就是为什么h的最大值是Integer.MAX_VALUE - (-low) -1的原因了
int j = low;
for(int k = 0; k < cache.length; k++) //缓存的最大范围是-128到MAX_VALUE - (-low) -1
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
3.toString方法/**
* 返回第一个参数用第二参数表示的字符串形式,第二个参数是进制数,默认是10进制
*
* 如果第一个参数是负的,那么返回结果中第一个字符是'-',如果第一个参数是正的,那么返回的结果中没有符号
* 结果中剩余的字符表示第一个参数的大小
*
* @see java.lang.Character#MAX_RADIX
* @see java.lang.Character#MIN_RADIX
*/
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* Use the faster version */
if (radix == 10) {
return toString(i);
}
char buf[] = new char[33]; //多存一个负号符号的位置
boolean negative = (i < 0);
int charPos = 32; //最后一个位置
if (!negative) { //统一成负数
i = -i;
}
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)]; //取余法进行进制转换,从buf的最后向前面添加
i = i / radix; //取整数部分
}
buf[charPos] = digits[-i]; //最后剩下一位单独处理
if (negative) { //如果是负数就添加'-'号
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos));
}
上一篇: Linux(Ubuntu)挂载Windows 磁盘
下一篇: 解决Error Hibernation device 'UUID=' a start job is running for dev-disk-by启动错误
推荐阅读
-
[Abp vNext 源码分析] - 11. 用户的自定义参数与配置
-
ZedGraph5.1.5源码分析去掉鼠标悬浮内容闪烁问题(附源码下载)
-
jQuery 源码分析(十一) 队列模块 Queue详解
-
Netty源码分析 (三)----- 服务端启动源码分析
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
java与c语言的区别有哪些(全面分析这3个基本区别)
-
spring源码分析系列5:ApplicationContext的初始化与Bean生命周期
-
spring源码分析6: ApplicationContext的初始化与BeanDefinition的搜集入库
-
Java并发系列之Semaphore源码分析
-
全面分析Java文件上传