听到这个问题的一瞬间,我的第一反应是:“口误吧?127和128肯定不一样啊~”,哈哈,你的呢?
其实这是一道大厂经典面试题,它触及了 Java 中 Integer 对象的创建和缓存机制的一个微妙之处。
一、new Integer("127")
- 总是在堆内存中创建一个新的 Integer 对象。
- 值为 127。
- 不使用整数缓存池。
二、Integer.valueOf("128")
- 创建一个新的 Integer 对象,值为 128。
- 不使用整数缓存池,因为 128 超出了默认缓存范围。
三、主要区别
1、对象创建
两种方式在这个例子中都会创建新对象。
2、缓存使用
new Integer("127") 不使用缓存。
Integer.valueOf("128") 也不使用缓存,但原因不同(超出范围)。
3、性能和内存:
在这个特定例子中,两者的性能和内存使用基本相同。
4、值的考虑:
127 在缓存范围内,但 new 关键字绕过了缓存。
128 超出缓存范围,所以 valueOf 方法会创建新对象。
四、对比示例
java
代码解读
复制代码
Integer a = new Integer("127"); Integer b = new Integer("127"); System.out.println(a == b); // false Integer c = Integer.valueOf("127"); Integer d = Integer.valueOf("127"); System.out.println(c == d); // true Integer e = Integer.valueOf("128"); Integer f = Integer.valueOf("128"); System.out.println(e == f); // false
整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
五、为什么说Integer.valueOf("128") 也不使用缓存,是因为超出了范围?
1、Integer 缓存是什么?
Java 的 Integer 类维护了一个内部缓存,用于存储经常使用的整数值。这个缓存就像一个预先准备好的数字集合。
默认情况下,这个缓存包含了 -128 到 127 之间的所有整数。
这个范围是经过 Java 开发者仔细考虑后选定的,因为这个范围内的数字在日常编程中使用频率最高。
2、为什么是 -128 到 127?
- 字节范围: 这个范围恰好对应一个字节(byte)可以表示的整数范围。
- 常用数字: 大多数日常计算和循环中使用的小整数都在这个范围内。
- 内存权衡: 缓存范围不能太大,否则会占用过多内存。
3、为什么 128 不在缓存中?
128 刚好超出了这个预定义的范围。
当你调用 Integer.valueOf("128") 时,Java 会检查这个数字是否在缓存范围内。
发现 128 超出范围后,Java 就会创建一个新的 Integer 对象,而不是使用缓存。
4、代码示例
java
代码解读
复制代码
Integer a = Integer.valueOf("127"); // 使用缓存 Integer b = Integer.valueOf("127"); // 使用缓存 System.out.println(a == b); // 输出 true,因为是同一个缓存对象 Integer c = Integer.valueOf("128"); // 不使用缓存,创建新对象 Integer d = Integer.valueOf("128"); // 不使用缓存,再次创建新对象 System.out.println(c == d); // 输出 false,因为是两个不同的对象
5、可以改变缓存范围吗?
是的,可以通过 JVM 参数 -XX:AutoBoxCacheMax= 来增加上限。
但是,下限 -128 是固定的,不能改变。
6、Integer对象比较
不要依赖于缓存机制来比较整数对象。
始终使用 .equals() 方法来比较 Integer 对象的值。
六、结论
虽然在给定的例子中("127" 和 "128"),两种方法都会创建新对象,但它们的行为原因不同:
new Integer("127") 总是创建新对象,无论值是多少。
Integer.valueOf("128") 创建新对象是因为 128 超出了缓存范围。
在实际应用中,除非特别需要新对象,否则推荐使用 Integer.valueOf() 或自动装箱,以便在可能的情况下利用缓存优化。
虽然了解这些细节很重要,但在日常编程中,我们应该专注于编写清晰、正确的代码,而不是过度依赖于这些底层优化。正确使用 .equals() 进行值比较,以及优先使用 valueOf() 或自动装箱,通常就足以编写高效且可靠的代码。