# 问题

26. Integer.valueOf(127) 和 Integer.valueOf(128) 有什么区别?

# 标准答案

Integer.valueOf(127)Integer.valueOf(128) 之间的区别在于,Integer.valueOf() 方法对于小于等于 127 的整数会返回缓存中的对象,而对于大于 127 的整数则会创建新的 Integer 对象。Java 在 Integer.valueOf() 方法中缓存了从 -128 到 127 的所有 Integer 对象,避免频繁创建新的对象,从而提高性能。

# 答案解析

# 核心原理:

Integer.valueOf() 方法是用于将给定的整数值转换为 Integer 对象。在 Java 中,Integer 类使用了缓存机制来优化性能。具体来说,Integer 对象的缓存范围默认是 -128 到 127。这是因为 Java 认为在这个范围内的整数在许多应用场景中会频繁使用,缓存这些对象可以减少对象的创建开销。

  1. 缓存机制的实现

    • 范围 -128 到 127:Java 默认在 Integer 类中为从 -128 到 127 之间的整数创建了一个缓存池。当你调用 Integer.valueOf() 方法时,如果传入的参数在缓存范围内,方法会直接返回缓存中的 Integer 对象,而不会创建新的对象。这种机制通过 IntegerCache 类实现。
    • 超出缓存范围:对于大于 127 或小于 -128 的整数,Integer.valueOf() 方法会创建一个新的 Integer 对象。这是因为这些值的使用频率较低,缓存的成本不值得。
  2. 为什么使用缓存?

    • 性能优化:频繁创建对象会增加 GC 的负担和内存的使用。通过缓存常用的 Integer 值,避免了不必要的对象创建,从而减少了内存消耗和性能开销。
    • 对象共享:对于缓存范围内的整数,无论何时何地使用该值,都会得到同一个对象引用,这有助于节省内存并确保一致性。
  3. Integer.valueOf() 方法实现

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high) {
            return IntegerCache.cache[i + 128];  // 返回缓存中的对象
        }
        return new Integer(i);  // 超出缓存范围,创建新的 Integer 对象
    }
    
    1
    2
    3
    4
    5
    6

    这里的 IntegerCache.lowIntegerCache.high 表示缓存的最小值和最大值,IntegerCache.cache 是存储整数缓存的数组。

# 常见错误:

  1. 忽视缓存机制:很多开发者可能没有意识到缓存机制的存在,因此可能错误地认为 Integer.valueOf(127)Integer.valueOf(128) 会返回不同的对象。这是因为只有 Integer.valueOf(128) 会创建一个新的对象,而 Integer.valueOf(127) 返回的是缓存中的对象。

  2. 对象比较错误:当开发者错误地将 == 用于比较 Integer 对象时,可能会得到意外的结果。特别是在缓存范围内,Integer 对象是共享的,使用 == 比较时会返回 true;而超出缓存范围时,== 比较会返回 false,因为它们是不同的对象。

# 最佳实践:

  1. 使用 Integer.valueOf() 而不是 new Integer()Integer.valueOf() 方法利用了缓存机制,是性能更好的选择。避免直接使用 new Integer() 来创建 Integer 对象,这样既浪费内存,也避免了对象的共享。

  2. 对象比较时使用 equals():在比较 Integer 对象时,应使用 equals() 方法,而不是 ==。尽管在缓存范围内 == 可以正常工作,但在超出缓存范围时会导致错误的比较结果。

  3. 理解缓存的范围:当需要频繁处理大量的整数时,了解 Integer.valueOf() 的缓存机制可以帮助开发者理解性能差异,并做出适当的优化决策。

# 性能优化:

  1. 避免创建不必要的对象:尽量避免使用 new Integer() 创建整数对象,改为使用 Integer.valueOf()。这样可以充分利用缓存机制,提高性能。

  2. 缓存策略:如果应用场景需要频繁处理大范围整数,可以考虑自己实现一个更广泛的缓存策略,或者使用 Integer.valueOf() 提供的默认缓存。

# 深入追问

🔹 IntegerCache 为什么选择 -128 到 127 作为缓存范围?这个范围如何优化性能? 🔹 在多线程环境中,Integer.valueOf() 会不会引发线程安全问题? 🔹 除了 Integer,其他包装类(如 ByteShortLong)是否也有类似的缓存机制?

# 相关面试题

  • Integer.valueOf()new Integer() 有什么区别?
  • Java 的自动装箱与拆箱机制是如何工作的?
  • Java 中的缓存机制是如何优化性能的?