欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深入研究Integer

程序员文章站 2024-03-08 15:58:52
...
Integer 数据类型在项目中随处可见,由于回想起曾经在使用 Inetger 时引发的一个bug,因此对 Integer 做一下深入的解析。

从举一个例子开始

public static void main(String[] args) {
	Integer num1 = 1;
	Integer num2 = 1;
	System.out.println(num1 == num2);
	
	Integer num3 = 200;
	Integer num4 = 200;
	System.out.println(num3 == num4);
}

最终输出的是:
true
false

num1==num2的输出是true,和预期结果一样。但是这里的num3和num4明明都是200,比较之后得到的却是false。

通过反编译源代码之后,有了发现

public static void main(String[] args){
    Integer num1 = Integer.valueOf(1);
    Integer num2 = Integer.valueOf(1);
    System.out.println(num1 == num2);
    
    Integer num3 = Integer.valueOf(200);
    Integer num4 = Integer.valueOf(200);
    System.out.println(num3 == num4);
}

原来在代码编译的时候,编译器自动把 Integer num1 = 1 编译成了 Integer num1 = Integer.valueOf(1)。 这个过程就是java包装类型的自动装箱
接着看一下 Integer.valueOf() 这个方法,它是Intetger提供的静态工厂方法,源码如下

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

再进去 IntegerCache 这个类看个究竟

private static class IntegerCache {
    static final int low = -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");
        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);
            } 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++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

IntegerCache 源码中分别定义了 low、high、cache[]

  • low 默认是-128,表示缓存的最小值
  • high 默认是127,表示缓存的最大值,high值可以通过JVM参数 -XX:AutoBoxCacheMax 来更改
  • cache[] 存放了 low 到 high 之间的所有值

最终看 valueOf() 的逻辑可以得出:

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

默认情况下:

  • 如果输入的int值在 -128 ~ 127之间,则返回的Integer对象是从 IntegerCache 的 cache 数组中取出来的对象,这也就是为什么num1会等于num2的原因;
  • 如果输入的int值不在 -128 ~ 127范围内,则每次返回的都是新的Integer对象,这也就是为什么num3不等于num4的原因;

如果想改变 IntegerCache 中的 high 值,可以通过JVM参数 -XX:AutoBoxCacheMax 来设置
深入研究Integer
启动时把 -XX:AutoBoxCacheMax 的值设置成10000,IntegerCache 在初始化的时候会读取配置的参数并进行设置,再次运行上面的例子,得到的结果便是
true
true

总结:
Integer的值缓存是为了在很多情况下,integer的值可能会应用在很多表示状态的值,例如:0-否,1-是; 1-未开始,2-进行中,3-已结束,这些场景下程序的性能都可以得到提升。为了避免踩坑,在包装类型间的相等判断建议用equals去比较,而不是 ==

相关标签: java