美文网首页
夯实 Java 基础2 - int 与 Integer 的区别

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

作者: 原水寒 | 来源:发表于2019-02-24 15:47 被阅读13次

    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<Integer> {
        // 包装的 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=<highValue>来指定
                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 的区别

          本文链接:https://www.haomeiwen.com/subject/cyodhqtx.html