大家好,这里是后端基础拾光集。今天我们来看ava 核心语法里面一个很容易踩坑的地方包装类与 Integer 缓存池陷阱
先看一段非常诡异的代码,很多人第一次运行都会怀疑是不是哪里出问题:
Integer a = 100; Integer b = 100; System.out.println(a == b); // true Integer c = 200; Integer d = 200; System.out.println(c == d); // false同样的写法,只是数字变了,结果直接反转。 很多同学偷懒,直接让 AI 写状态码判断逻辑,AI 随手就写出这种代码。本地测试全通过,上线之后,偶尔出现判断失效,bug 很难复现,排查到崩溃。
int 和 Integer,到底差在哪?
int 就是原始基础类型,就像写在便签纸上的数字,只是单纯数值。 Integer 是包装类,相当于存钱罐。
存钱罐里面装数字,存钱罐本身是一个独立物件。 两个存钱罐,哪怕里面金额一模一样,罐子本身也不是同一个东西。
==比较存钱罐的时候,看的是是不是同一个罐子,不是看里面钱是不是一样。
Integer 缓存池是什么?
Java 提前预制了一批存钱罐,放在一个公共柜子里,这个柜子就是Integer 缓存池。 柜子里面提前做好了 -128 到 127 的存钱罐。 当你写Integer a =100,底层自动调用Integer.valueOf(100),直接从柜子拿现成存钱罐,不用新造。 所以 a 和 b,拿到的是同一个罐子,==对比地址,返回 true。
但是数字超过 127,柜子里没有存货,Java 只能每次全新打造一个存钱罐。 200,c 和 d 是两个完全独立的存钱罐,罐子不一样,==返回 false。
一句话记忆:小数字共用存钱罐,大数字每次换新罐子。
区分两种极易混淆场景
场景 1:包装类 == 基础类型(int)👉自动拆箱,比较数值(AI 最爱踩的坑)
Integer status = 200; if(status == 200) { } // status拆箱成int,比较数字大小,不会触发缓存池陷阱场景 2:包装类 == 包装类(两个 Integer 对象对比)👉对比对象地址,缓存池坑就在这里
Integer c = 200; Integer d = 200; System.out.println(c == d); // 两个对象对比地址,200超出缓存池,返回false!这才是经典坑那为什么开发里依然不推荐写status == 200?
- 如果 status 是 null,自动拆箱直接空指针异常
NullPointerException!
Integer status = null; if(status == 200){ // 拆箱 status.intValue() 直接NPE崩溃 }这才是业务代码里最大风险,不是缓存池问题,是 null 空指针。
- AI 很容易混淆这两种写法,一不小心写成两个包装类互相比较:
Integer a = getStatus(); Integer b = getCode(); if(a == b) { } // 两个Integer对象对比地址,缓存池陷阱复现!✅推荐写法
方案 A(优先推荐,规避 NPE)
if(Integer.valueOf(200).equals(status)){ System.out.println("请求成功"); }equals 打开存钱罐,只对比里面的数字,同时天然规避空指针风险。status 为 null 时,
equals不会触发空指针,直接返回 false。
方案 B:如果你坚持用 ==,必须先判 null
if(status != null && status == 200){ System.out.println("请求成功"); }✅核心总结
- int 是纸上数字;Integer 是存钱罐(对象)。
- Integer 缓存池预制了 -128 ~ 127 的对象,复用实例。
==对比对象地址(是不是同一个罐子);equals 对比里面数值。- 两个 Integer 包装对象对比,禁止直接
==;包装类和基础类型==会自动拆箱,但要警惕 null 导致空指针。业务推荐用equals。
📚系列专栏:后端基础拾光集
本系列结合生活化案例讲解 Java 底层原理,覆盖面试、生产开发高频知识点。
欢迎点赞收藏+关注,不错过后续更新。
已更新:集合底层源码、红黑树、泛型、Java 异常、Spring 事务七大陷阱等。
如有疑问欢迎评论区留言讨论。