极高 基础
包装类与自动装箱#
一句话答案#
8 种基本类型各有对应包装类,自动装箱(
Integer.valueOf)/拆箱(intValue)由编译器插入;Integer缓存了 -128~127,该区间内==比较为 true,区间外为 false,所以包装类比较值必须用equals。
核心要点
1. 八种基本类型与包装类
| 基本类型 | 包装类 | 字节 | 缓存范围 |
|---|---|---|---|
| byte | Byte | 1 | 全部(-128~127) |
| short | Short | 2 | -128~127 |
| int | Integer | 4 | -128~127(上限可调) |
| long | Long | 8 | -128~127 |
| float | Float | 4 | 无缓存 |
| double | Double | 8 | 无缓存 |
| char | Character | 2 | 0~127 |
| boolean | Boolean | - | TRUE/FALSE 两个 |
2. 自动装箱/拆箱的本质
编译器语法糖,反编译可见:
Integer a = 100; // 编译为 Integer.valueOf(100)
int b = a; // 编译为 a.intValue()java3. 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 也有同样的 -128
127 缓存,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 也缓存小数值”——浮点取值连续,没有缓存