integer 最大值_Integer源码分析——上 (jdk11)

db2fb9f0c8595b066837b97e90164506.png
  • Integer简述

Integer是JDK1.5出现的int原生类型的包装类型,在JDK9之前版本,通常是使用构造函数的方式创建对象:

Integer integer = new Integer(1); 

从JDK9开始之后,通过构造方法这种方式创建Integer对象的方式被抛弃,使用Integer提供的静态方法来创建对象:

Integer integer = Integer.valueOf(1);

Integer为用户创建integer对象提供了基于int和String的两种类型的方式:

下面主要讨论的基于jdk11的源码进行分析。

  • Integer基本属性
//Integer可以装箱的int最小值,采用16进制表示@Native public static final int   MIN_VALUE = 0x80000000;//Integer可以装箱的int最大值@Native public static final int   MAX_VALUE = 0x7fffffff;//实际保存原生int的值private final int value;//表示的Integer所表示的int类型占32位@Native public static final int SIZE = 32;//表示int的字节数public static final int BYTES = SIZE / Byte.SIZE;//所有的数子和字母字符static final char[] digits = {        '0' , '1' , '2' , '3' , '4' , '5' ,        '6' , '7' , '8' , '9' , 'a' , 'b' ,        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,        'o' , 'p' , 'q' , 'r' , 's' , 't' ,        'u' , 'v' , 'w' , 'x' , 'y' , 'z'    };
  • Integer.valueOf(int i)

下面先看源码:

@HotSpotIntrinsicCandidatepublic static Integer valueOf(int i) {    if (i >= IntegerCache.low && i <= IntegerCache.high)          return IntegerCache.cache[i + (-IntegerCache.low)];    return new Integer(i);}

根据上面的源码,我们可以看到出现了一个IntegerCache类,该类的作用是缓存一部分int类型的自动装箱的对象值,默认情况下是缓存-128到127之间256个数字,也就是说,在jvm中无论调用几次Integer.valueOf(1),最后只会在jvm中存在一个对象。这个缓存的最大值可以在启动jvm的时候置,通过-XX:AutoBoxCacheMax=进行设置。下面具体看一下IntegerCache类的实现:

private static class IntegerCache {        static final int low = -128;//定义了缓存的最小值        static final int high; //用来存储最大的缓存数值        //保存jvm创建的所有的范围在low和high之间的对象        static final Integer cache[];        static {            // 默认是127            int h = 127;            //如果启动JVM的时候设置了-XX:AutoBoxCacheMax参数,那么改参数值会保存到            //java.lang.Integer.IntegerCache.high此环境变量中            String integerCacheHighPropValue =                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");            if (integerCacheHighPropValue != null) {                try {                    //把字符串转换为数字                    int i = parseInt(integerCacheHighPropValue);                    //户设置的新的最大int值应该大于127                    i = Math.max(i, 127);                    //此行的目的确保最大值小于Integer.MAX_VALUE - (-low) -1                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);                } catch( NumberFormatException nfe) {                    // If the property cannot be parsed into an int, ignore it.                }            }            high = h;            //创建保存缓存对象的数组            cache = new Integer[(high - low) + 1];            int j = low;            //缓存中的对象会被全部创建出来,而不是在用到某一个再去创建某一个            for(int k = 0; k < cache.length; k++)                cache[k] = new Integer(j++);                       assert IntegerCache.high >= 127;        }        private IntegerCache() {}    }

上面的代码中h = Math.min(i, Integer.MAX_VALUE - (-low) -1);有的人可能不理解,下面重点解释一下。IntegerCache通过它内部定义的数组来保存Integer的缓存对象。在Java中数组的最大元素个数是Integer.MAX_VALUE,由于IntegerCache还会保存128个复数和0。因此IntegerCache数组大小:

cache.size = 128+1+h(最大正数)

所以h的最大值是Integer.MAX_VALUE - (-low) -1

由上面的源码可知,当IntegerCache第一次被使用的时候,jvm就会创建所有的在缓存范围内的Integer对象。

下面的代码表示当我们需要创建的Integer对象不再缓存的范围内,才会去调用构造方法去创建新对象

 if (i >= IntegerCache.low && i <= IntegerCache.high)          return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i);

至于Integer的构造方法比较简单:

@Deprecated(since="9")public Integer(int value) {        this.value = value;}
  • valueOf(String s)

此方法的具体实现如下:

public static Integer valueOf(String s) throws NumberFormatException {    return Integer.valueOf(parseInt(s, 10));}

首先调用parseInt方法把传入的字符串转换为int值,然后再调用上面提到的valueOf(int i)方法。

下面介绍一下parseInt的实现原理:

public static int parseInt(String s, int radix)            throws NumberFormatException{      boolean negative = false;    int i = 0, len = s.length();    int limit = -Integer.MAX_VALUE;    if (len > 0) {        char firstChar = s.charAt(0);        //判断一个字符是不是是 '-'        if (firstChar < '0') {            if (firstChar == '-') {                negative = true;                limit = Integer.MIN_VALUE;            } else if (firstChar != '+') {                throw NumberFormatException.forInputString(s);            }            if (len == 1) {                 throw NumberFormatException.forInputString(s);            }            i++;        }        int multmin = limit / radix;        int result = 0;        //避免溢出        while (i < len) {            int digit = Character.digit(s.charAt(i++), radix);            if (digit < 0 || result < multmin) {                throw NumberFormatException.forInputString(s);            }            result *= radix;            if (result < limit + digit) {                throw NumberFormatException.forInputString(s);            }            result -= digit;        }        return negative ? result : -result;    } else {        throw NumberFormatException.forInputString(s);    }}

在parseInt方法的主要实现原理就是,从左到右获取字符串中的每个数字字符,将数字字符转换为对应的数字:

int digit = Character.digit(s.charAt(i++), radix);

然后把上一轮转换的结果进行扩展(result是保存每一数字处理后的结果):

result *= radix;//一般转换的是十进制数据,因此radix=10

然后把加上result的值加上本次获取digit,也就是说正常的逻辑是:

比如转换的字符为:str="3425"

1.因为str长度为4,因此需要循环4次,第一次获取第一个数字为3,本次循环结果result=3

2.第二次循环,获取到的数字为4,然后计算本次循环结果result = 3*10 +4,result = 34

3.第三次循环,获取到的数字为2,然后计算本次循环结果result = 34*10 +2,result = 342

4.第四次循环,获取到的数字为5,然后计算本次循环结果result = 342*10 +5,result = 3425

作者这里却用到了一种特殊的方式,就是使用负数的方式:

result -= digit;

这样做的目的就是为了预付需要转换的数字字符串出现溢出:

//下面的代码当出现上溢或者下溢的时候执行  例如需要转换的字符串为:"-21474836490"或者"21474836490"if (result < limit + digit) {   throw NumberFormatException.forInputString(s);}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值