如何通过包装类高效转换基本类型与对象间数据?
- 内容介绍
- 相关推荐
本文共计859个文字,预计阅读时间需要4分钟。
Java 中,`int` 和 `boolean` 是基本类型,不继承自 `Object` 类型。因此,不能直接将这些基本类型转换为 `Object` 类型,也不能使用 `ArrayList`、泛型方法或 `equals()` 方法。例如,直接尝试将 `int` 类型转换为 `Object` 类型会编译错误,错误信息为:
包装类(Integer、Boolean 等)就是为解决这个而生的:它们是真正的类,有字段、方法、能 null,还能参与多态。
Integer.valueOf() 比 new Integer() 强在哪
手动 new Integer(42) 会无条件创建新对象,浪费内存;而 Integer.valueOf(42) 在 -128 到 127 范围内复用缓存对象(JLS 规定),既快又省。
- 推荐始终用
valueOf(),包括Boolean.valueOf()、Double.valueOf() -
new方式已过时,且在 == 比较时容易出错(见下一条) - 注意:
valueOf()对Long、Integer有缓存,但Float和Double的valueOf()不缓存(除非值是 0.0、1.0 等极少数常量)
用 == 比较包装类,90% 是错的
基本类型用 == 没问题,但包装类用 == 实际比较的是引用地址,不是值。尤其当一个来自缓存、一个来自 new,或超出缓存范围时,结果反直觉:
Integer a = Integer.valueOf(100); // 缓存内 Integer b = Integer.valueOf(100); // 同一对象 System.out.println(a == b); // true Integer c = Integer.valueOf(200); // 超出缓存,默认不复用 Integer d = Integer.valueOf(200); System.out.println(c == d); // false!但 c.equals(d) 是 true
- 一律用
.equals()比较包装类值(注意:null会 NPE,必要时先判空) - 如果确定非
null且在缓存范围内,==可能更快,但可读性和安全性远不如.equals() - 自动拆箱(如
int x = myInteger;)遇到null会抛NullPointerException,比 == 更隐蔽
泛型容器里别依赖自动装箱做“类型擦除补偿”
写 ArrayList<integer></integer> 时,你希望它只存整数。但编译后类型被擦除,运行时实际是 ArrayList,底层仍靠装箱/拆箱维持语义。这带来几个实际限制:
- 不能声明
ArrayList<int></int>—— 泛型不支持基本类型,必须用包装类 - 高频增删数值(比如百万级循环)时,频繁装箱/拆箱 + GC 压力明显,考虑用
IntArrayList(如 Eclipse Collections 或 Trove 库) - 序列化时,
Integer比int多存对象头和引用信息,体积略大 - JSON 库(如 Jackson)默认把
Integer序列化成数字,但如果字段为null,可能输出null字符串而非跳过,需配置@JsonInclude(JsonInclude.Include.NON_NULL)
包装类不是“透明代理”,它是有行为、有生命周期、有内存开销的真对象。用之前想清楚:这里到底需要对象能力,还是只是被迫迁就 API?
本文共计859个文字,预计阅读时间需要4分钟。
Java 中,`int` 和 `boolean` 是基本类型,不继承自 `Object` 类型。因此,不能直接将这些基本类型转换为 `Object` 类型,也不能使用 `ArrayList`、泛型方法或 `equals()` 方法。例如,直接尝试将 `int` 类型转换为 `Object` 类型会编译错误,错误信息为:
包装类(Integer、Boolean 等)就是为解决这个而生的:它们是真正的类,有字段、方法、能 null,还能参与多态。
Integer.valueOf() 比 new Integer() 强在哪
手动 new Integer(42) 会无条件创建新对象,浪费内存;而 Integer.valueOf(42) 在 -128 到 127 范围内复用缓存对象(JLS 规定),既快又省。
- 推荐始终用
valueOf(),包括Boolean.valueOf()、Double.valueOf() -
new方式已过时,且在 == 比较时容易出错(见下一条) - 注意:
valueOf()对Long、Integer有缓存,但Float和Double的valueOf()不缓存(除非值是 0.0、1.0 等极少数常量)
用 == 比较包装类,90% 是错的
基本类型用 == 没问题,但包装类用 == 实际比较的是引用地址,不是值。尤其当一个来自缓存、一个来自 new,或超出缓存范围时,结果反直觉:
Integer a = Integer.valueOf(100); // 缓存内 Integer b = Integer.valueOf(100); // 同一对象 System.out.println(a == b); // true Integer c = Integer.valueOf(200); // 超出缓存,默认不复用 Integer d = Integer.valueOf(200); System.out.println(c == d); // false!但 c.equals(d) 是 true
- 一律用
.equals()比较包装类值(注意:null会 NPE,必要时先判空) - 如果确定非
null且在缓存范围内,==可能更快,但可读性和安全性远不如.equals() - 自动拆箱(如
int x = myInteger;)遇到null会抛NullPointerException,比 == 更隐蔽
泛型容器里别依赖自动装箱做“类型擦除补偿”
写 ArrayList<integer></integer> 时,你希望它只存整数。但编译后类型被擦除,运行时实际是 ArrayList,底层仍靠装箱/拆箱维持语义。这带来几个实际限制:
- 不能声明
ArrayList<int></int>—— 泛型不支持基本类型,必须用包装类 - 高频增删数值(比如百万级循环)时,频繁装箱/拆箱 + GC 压力明显,考虑用
IntArrayList(如 Eclipse Collections 或 Trove 库) - 序列化时,
Integer比int多存对象头和引用信息,体积略大 - JSON 库(如 Jackson)默认把
Integer序列化成数字,但如果字段为null,可能输出null字符串而非跳过,需配置@JsonInclude(JsonInclude.Include.NON_NULL)
包装类不是“透明代理”,它是有行为、有生命周期、有内存开销的真对象。用之前想清楚:这里到底需要对象能力,还是只是被迫迁就 API?

