基本类型变量初始化不触发自动装箱,真正开销来自赋值给包装类引用或在泛型集合等对象上下文中使用时的隐式装箱;Integer i = 100、list.add(42)、Integer[] arr = {1,2,3} 等场景会触发装箱,而 int j = 100 不会;装箱开销在于堆内存分配、GC压力及null拆箱异常;避免策略包括优先使用基本类型、原始类型集合、显式valueOf()及静态常量用int而非Integer。

基本类型变量初始化本身不触发自动装箱,因此完全不影响性能。真正带来开销的,是把基本类型值赋给包装类引用、或在需要对象的上下文中使用基本类型(比如放进泛型集合、作为方法参数传递等)时发生的隐式装箱操作。
哪些初始化场景会触发装箱?
只有涉及包装类声明和赋值时才可能装箱,基本类型声明(如 int x = 5;)全程都在栈上操作,无对象创建、无GC压力。
-
Integer i = 100; → 触发自动装箱(实际调用
Integer.valueOf(100)) - int j = 100; → 纯基本类型,无装箱,零开销
-
List<Integer> list = new ArrayList<>(); list.add(42); →
add()参数需Integer,42 被装箱 - Integer[] arr = {1, 2, 3}; → 每个字面量都触发一次装箱
装箱开销具体在哪?
不是“慢在转换”,而是背后隐含的资源动作:
- 每次装箱都可能新建对象(超出缓存范围如
Integer.valueOf(200)就一定 new) - 对象分配消耗堆内存,增加 GC 频率(尤其高频循环中)
- 拆箱时若对象为
null,直接抛NullPointerException - 缓存仅覆盖有限范围(
Integer是 -128 到 127),边界外无优化
怎么写才真正避免不必要装箱?
核心原则:能用基本类型就别用包装类,尤其在计算密集或数据量大的地方。
- 局部计算变量统一用
int/long/double,而非Integer/Long - 循环累加不用
Long sum = 0L,改用long sum = 0L - 集合确实需要存数值时,优先考虑第三方库的原始类型集合(如 Eclipse Collections 的
IntList、Trove 的TIntArrayList) - 必须用包装类时,显式调用
valueOf()比直接赋值更可控(便于识别装箱点)
一个容易被忽略的初始化陷阱
静态常量或字段初始化中看似“简单”的赋值,也可能藏装箱:
-
private static final Integer DEFAULT_CODE = 200;→ 每次类加载都装箱一次(虽只一次,但若大量类似定义仍累积) -
private final int code = 200;→ 推荐写法,编译期常量,无运行时开销 - 构造函数参数若为包装类型(如
public User(Integer id)),传入new User(123)仍会装箱,不如定义为public User(int id)



















