夯实 Java 基础2 - int 与 Integer 的区别

Java 有8种基本类型:byte/short/int/long/float/double/char/boolean,对应有8种包装类:Byte/Short/Integer/Long/Float/Double/Character/Boolean。

  • 一、Integer 的缓存机制
  • 二、拆箱与装箱
  • 三、int 与 Integer 的使用场景

下面以 int 与 Integer 为例,说明一些细节点。

一、Integer 的缓存机制

        // 1. 默认缓存范围 -128~127
        System.out.println(Integer.valueOf(127) == Integer.valueOf(127)); // true
        System.out.println(Integer.valueOf(128) == Integer.valueOf(128)); // false

        // 2. 指定缓存范围最大值 -XX:AutoBoxCacheMax=128,-128~128
        System.out.println(Integer.valueOf(128) == Integer.valueOf(128)); // true
        System.out.println(Integer.valueOf(129) == Integer.valueOf(129)); // false

        System.out.println("====== end ======");
  • Integer 默认缓存的 int 范围是 [-128, 127],此范围内的值使用享元模式,即只保留一份,例如 1 这个数字,存储在 IntegerCache 中,每次获取,取到的都是同一个 Integer 对象
  • 缓存的最大值可以通过 -XX:AutoBoxCacheMax=highValue 来指定
  • 缓存范围内的值可以使用 == 来判断相等,因为是同一个 Integer,缓存范围之外的需要使用 equals 进行相等判断,Integer#equals 内部实际上比较包装的 int value
  • 使用 Integer.valueOf 可以使用到缓存,使用 new Integer 每次都会创建新的对象,不会使用缓存,所以 尽量使用 Integer.valueOf
public final class Integer extends Number implements Comparable {
    // 包装的 int 对象
    private final int value;

    public static Integer valueOf(int i) {
        // 从缓存范围获取数据,缓存范围之外的直接 new
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            // equals 比较 int value
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

    // 缓存类
    private static class IntegerCache {
        static final int low = -128; // 最小值
        static final int high; // 最大值
        static final Integer cache[]; // 缓存结果集
        
        static {
            // high 可以通过 -XX:AutoBoxCacheMax=来指定
            int h = 127;
            // 1. 获取 high
            String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                ...
            }
            high = h;
            // 2. 创建缓存器,并初始化 Integer 对象到其中
            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;
        }
    }
}

二、拆箱与装箱

  • 装箱与拆箱是编译器来做的,装箱代码 Integer x = 1,编译器会编译为 Integer x = Integer.valueOf(1);拆箱代码 int y = x,编译器会编译为 int y = x.intValue()
  • 由于装箱使用了 Integer.valueOf,所以也会走缓存
Integer x = 1; // 自动装箱
int y = x; // 自动拆箱

字节码:

       1: invokestatic  #2   // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6: invokevirtual #3   // Method java/lang/Integer.intValue:()I

三、int 与 Integer 的使用场景

  • 对于性能极其敏感的情况下,使用 int 可以避免创建对象,不仅节省创建对象的时间,还节省内存,因为一个对象的话会有额外的对象头和补齐填充;
  • int[] 占用连续内空间,Integer[] 不是,所以 int[] 操作起来更高效。

问题:

  1. int 存放在哪里?是否有内存安全问题?

你可能感兴趣的:(夯实 Java 基础2 - int 与 Integer 的区别)