面试知识库
极高 基础

包装类与自动装箱#

一句话答案#

8 种基本类型各有对应包装类,自动装箱(Integer.valueOf)/拆箱(intValue)由编译器插入;Integer 缓存了 -128~127,该区间内 == 比较为 true,区间外为 false,所以包装类比较值必须用 equals

核心要点

1. 八种基本类型与包装类

基本类型包装类字节缓存范围
byteByte1全部(-128~127)
shortShort2-128~127
intInteger4-128~127(上限可调)
longLong8-128~127
floatFloat4无缓存
doubleDouble8无缓存
charCharacter20~127
booleanBoolean-TRUE/FALSE 两个

2. 自动装箱/拆箱的本质

编译器语法糖,反编译可见:

Integer a = 100;        // 编译为 Integer.valueOf(100)
int b = a;              // 编译为 a.intValue()
java

3. Integer 缓存(IntegerCache)

valueOf 对 -128~127 返回缓存对象,区间外 new Integer()

Integer a = 127, b = 127;
System.out.println(a == b);   // true  → 同一缓存对象
Integer c = 128, d = 128;
System.out.println(c == d);   // false → 两个不同对象
java
  • 缓存上限可通过 -XX:AutoBoxCacheMax=N-Djava.lang.Integer.IntegerCache.high=N 调高。
  • Float/Double 没有缓存(取值连续无意义)。

4. 常见陷阱

  • 拆箱 NPE:包装类为 null 时自动拆箱抛 NullPointerException
Integer x = null;
int y = x;        // 运行期 NPE(x.intValue())
java
  • 三元运算符强制拆箱true ? new Integer(1) : new Double(2) 会把 Integer 拆箱再转 double,结果 1.0。
  • 包装类与基本类型混合比较会拆箱:Integer(1000) == 1000 为 true(包装类拆箱成 int 比较值)。
面试回答(2分钟版)

Java 有 8 种基本类型,每种都有对应的包装类,比如 int 对应 Integer。自动装箱和拆箱是编译器提供的语法糖,装箱实际调用的是 Integer.valueOf,拆箱调用的是 intValue。这里最经典的面试坑是 Integer 缓存:valueOf 方法对 -128 到 127 之间的值会返回缓存好的对象,所以这个区间内两个相同的 Integer 用 == 比较是 true,但超过 127 比如 128,每次都是 new 出来的新对象,== 就是 false。这就是为什么包装类比较值一定要用 equals 而不是 ==。缓存上限可以通过 JVM 参数 AutoBoxCacheMax 调高,Byte/Short/Long 也有同样的 -128127 缓存,Character 缓存 0127,但 Float 和 Double 因为取值连续没有缓存。另外两个高频坑:一是包装类为 null 时自动拆箱会抛空指针异常,所以从数据库或 Map 取出的 Integer 直接赋值给 int 要小心;二是三元运算符如果两个分支类型不一致会触发拆箱和类型提升,可能得到意料之外的结果。

追问与易错

追问方向:

  • “Integer a=127,b=127 和 a=128,b=128 的 == 结果?”→ 前者 true(命中 -128~127 缓存返回同一对象),后者 false(超出缓存范围,valueOf 各 new 一个对象)
  • “为什么包装类要做缓存?”→ 小整数使用极频繁,缓存避免重复创建对象、降低 GC 压力,是享元模式的体现
  • “什么时候会触发自动拆箱导致 NPE?”→ 包装类为 null 时赋值给基本类型、参与算术运算、用于 ==/三元运算符中的类型提升时
  • “new Integer(1) 和 Integer.valueOf(1) 区别?”→ 前者必定新建对象,后者命中缓存可能复用;JDK 9 起 new Integer 已 @Deprecated,推荐 valueOf
  • “Long l = 1L; l == 1L 结果?”→ true,右侧是基本类型,会把 Long 拆箱成 long 比较值,而非比较引用

易错点:

  • ❌ “包装类比较用 ==“——只在 -128~127 缓存区间内偶然为 true,必须用 equals 比较值
  • ❌ “自动拆箱不会出错”——null 包装类拆箱抛 NPE,是生产事故高发点
  • ❌ “Float/Double 也缓存小数值”——浮点取值连续,没有缓存