IntegerCache 逐行解析

73 阅读3分钟

IntegerCache是Integer中的静态类,用于构建[-128,127]的数组缓存

//首先,它是Integer的一个静态内部类
private static class IntegerCache {
  	//[-128,high]
    static final int low = -128;
    static final int high;
    static final Integer[] cache;
    static Integer[] archivedCache;

    static {
        // high value may be configured by property
      	// high 默认为127
        int h = 127;
      	// 这里会从启动配置中读取配置,设置最大缓存长度
     	 	// 缓存的大小可以通过该 -XX:AutoBoxCacheMax=<size> 选项控制
        String integerCacheHighPropValue =
            VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
              	// 这里和127比较,Math.max(a,b)方法 a>=b时,都会取a
              	// 这里的目的是为了控制最大值为127(数组下标从0开始,所以ingeger[127]放的是127)
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
              	// (a,b)-> a<=b 取a
              	// 这里是为了保障 不会超过数组长度 2^32-1 [-128,2^32-128-1] 最大的数组长度是 2^32 - 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;

        // Load IntegerCache.archivedCache from archive, if possible
        VM.initializeFromArchive(IntegerCache.class);
      	// 算出数组的长度length 因为数组长度要比实际的数字大1,所以+1
        int size = (high - low) + 1;

        // Use the archived cache if it exists and is large enough
      	// 判断archivedCache是不是为空,构架的时候,size是不是大于缓存的长度
        if (archivedCache == null || size > archivedCache.length) {
          	//创建一个size长度的数组 对应 int size = (high - low) + 1;
            Integer[] c = new Integer[size];
            int j = low;
          	// 根据size的长度进行循环写入数据到数组,起始值从low开始
          	// 这里就能看出来 数组是[-128,-127,-126]
          	// [0] = -128, [1] = -127, [2] = -126
            for(int k = 0; k < c.length; k++)
                c[k] = new Integer(j++);
            archivedCache = c;
        }
        cache = archivedCache;
        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

结论

比较Integer类型对象是否相同,不要用==,==和!= 比较的是对象的引用,最好用方法里的equals()方法,因为==比较的是引用,当你的数字是[-128,high]时,Ingeger会先从IntegeCache里面取值

笔记

IntegeCache 可以通过 -XX:AutoBoxCacheMax= 选项high大小

比较大小后取值,可以用 Math.max(a,b) 和 Math.min(a,b)

断言关键字的使用,需要配置 VM options才会生效 -ea, 默认是不生效的

assert IntegerCache.high >= 127;

比较float类型时,不要使用==,Float类型时不要用equals(),会有精度问题 简单来说,就是float运算的过程中,四舍五入后,难免会有超低的精度偏差 比如 1.1 和 1.10000000001,是运算时出现的

public static void main(String[] args) {
        float x= 0.0f;
        for (int i = 0; i < 11; i++) {
            x+=0.1f;
        }
        float y= 0.1f*11;

        //1.1000001
        System.out.println(x);
        //1.1
        System.out.println(y);
        //false
        System.out.println(x==y);
    }

上面的代码中,一个是0.1+11次,一个是0.1*11,运算结果,应该是一致的,却出现了精度的偏差(具体为毛还不清楚),所以运算完直接 用==或者equals()比较数据是不准确的 针对这种情况,我们可以用BigDecimal去处理数据

BigDecimal 是不可变的,能够精确地表示十进制数字。需要注意的是,创建 BigDecimal 对象时,要使用参数为 String 的构造方法,不要使用构造参数为 double 的,如果非要使用 double 创建,一定要用 valueOf 静态方法,防止丢失精度。然后调用 compareTo 方法比较即可