当前位置: 首页 > backend >正文

自动拆箱和装箱的原理与作用

自动装箱(Autoboxing)和拆箱(Unboxing)是 Java 5 引入的重要特性,用于简化基本数据类型与其对应的包装类之间的转换过程。

基本数据类型与包装类的区别

一、自动装箱拆箱

装箱:是的过程。eg:

自动装箱(Autoboxing)

定义 : 是编译器第一个特性,编译器会在编译时会自动将基本类型转换为对应的包装类对象。egint类型转换为Integer,将double转换为Double。

底层机制:实质上是编译器自动调用了包装类的 valueOf()方法。

  • 示例 :将一个int赋值给一个Integer对象时,Java编译器自动插入了Integer.valueOf(int)
Integer i = 10;
// 编译器自动转换为 Integer i = Integer.valueOf(10);
  • valueOf()方法有可能通过缓存(如Integer的缓存区间-128到127)来提供效率。

自动拆箱 (Unboxing):

定义: 编译器在编译时会自动将包装类对象转换为对应的基本数据类型。eg:将 Integer 转换为 int,将 Double 转换为 double 等。

底层机制:实质上是调用了包装类的 xxxValue()方法(例如 Integer.intValue()

  • 示例:将一个Integer对象赋值给一个int变量时,Java编译器自动调用了.intValue()
Integer boxedA = 10;
int a = boxedA;
// 编译器自动转换为 int a = boxedA.intValue();

二、包装类与基本数据类型的对应关系

基本类型

包装类

装箱方法

拆箱方法

byte

Byte

Byte.valueOf(byte)

byteValue()

short

Short

Short.valueOf(short)

shortValue()

int

Integer

Integer.valueOf(int)

intValue()

long

Long

Long.valueOf(long)

longValue()

float

Float

Float.valueOf(float)

floatValue()

double

Double

Double.valueOf(double)

doubleValue()

char

Character

Character.valueOf(char)

charValue()

boolean

Boolean

Boolean.valueOf(boolean)

booleanValue()

三、装箱和拆箱的作用(引入原因)

1、 Java 5之前,基本类型和对象之间需要手动转换,自动装箱和拆箱可以减少显式转换的代码,使代码更简洁。

2、Java 的集合框架只能存储对象,不能直接存储基本类型。装箱和拆箱使得在集合中使用基本类型变得更加方便。

3、 装箱和拆箱允许基本类型和对象类型之间的无缝转换,使得在方法参数、返回值等场景中可以更灵活地处理数据。

四、性能影响

尽管装箱和拆箱简化了代码,但它们也带来了一些性能上的开销:装箱会创建新的对象,这会带来内存分配和垃圾回收的开销。在拆箱过程中,如果包装类对象为 null,会抛出空指针异常

1、性能开销

对象创建开销:每次装箱(除非命中缓存)都会在堆上创建一个新对象。如果在一个庞大的循环或性能关键的方法中频繁装箱,会产生大量短期对象,增加垃圾回收(GC)的压力,可能导致GC频繁,从而影响程序性能。

方法调用开销:拆箱操作需要调用xxxValue()方法,虽然后期JVM会进行优化,但在极端情况下仍可能带来微秒级的开销。

优化:在循环、高频计算等性能敏感场景,优先使用基本类型

反面案例

// 避免在循环中使用自动装箱
long start = System.currentTimeMillis();
Long sum = 0L; // 包装类
for (long i = 0; i < Integer.MAX_VALUE; i++) {sum += i; // 每次循环发生:拆箱(sum->long) -> 加法 -> 装箱(结果->Long)}
long duration = System.currentTimeMillis() - start;
System.out.println("使用Long耗时:" + duration + "ms");// 使用基本类型
start = System.currentTimeMillis();
long sumPrimitive = 0; // 基本类型
for (long i = 0; i < Integer.MAX_VALUE; i++) {sumPrimitive += i; // 无装箱拆箱}
duration = System.currentTimeMillis() - start;
System.out.println("使用long耗时:" + duration + "ms");
使用Long耗时:8047ms
使用long耗时:1001ms

2、NPE异常(空指针异常)

对一个null引用的包装类对象进行拆箱操作时,会抛出NPE

Integer value=null;
//抛出NullPointerException
intunboxed= value; // 拆箱时相当于调用null.intValue()
// 正确做法:拆箱前进行null检查
if (possibleNull != null) {int value = possibleNull;
}Map<String, Integer> map = new HashMap<>();
// int value = map.get("someKey"); // 如果key不存在,get返回null,拆箱则NPE
Integer value = map.get("someKey");
if (value != null) {//拆箱前进行null检查int safeValue = value;
}// 三元表达式中更隐晦的NPE
booleanflag=true;
Integerresult= flag ? null : 0; 
intvalue= result; // 可能触发NPE

3、性能优化(缓存、使用 equals()比较包装类对象的值

Integer缓存:默认缓存了 -128 到 127 之间的值。通过 Integer.valueOf(int i)方法获取时,如果值在此范围内,会直接返回缓存池中已存在的对象;如果超出此范围,才会创建新的 Integer对象。

其他包装类缓存范围

  • • Byte:全部值缓存(-128~127)
  • • Short, Integer, Long:-128~127(可配置上限)
  • • Character:0~127
  • • Boolean:truefalse两个值缓存

缓存机制带来的陷阱:使用 ==比较包装对象时,==比较的是对象引用(内存地址),而不是值。对于不在缓存范围内的值,即使值相等,==比较也会返回 false

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true, 缓存池中的同一个对象Integer c = 128;
Integer d = 128;
System.out.println(c == b); // false, 超出缓存范围,是两个不同的对象
System.out.println(c.equals(d)); // true, 总是使用equals来比较值

五、实际应用场景

1、集合

// 自动装箱允许基本类型直接放入集合
List<Integer> numbers = new ArrayList<>();
numbers.add(5); //自动装箱:Integer.valueOf(5)
numbers.add(10);// 自动拆箱从集合中获取值
int first = numbers.get(0); // 自动拆箱:numbers.get(0).intValue()

2、方法传参

public void process(Integer value) {// 自动拆箱使用    int result = value * 2;    System.out.println(result);
}
// 调用时可以传递基本类型
process(15); // 自动装箱:Integer.valueOf(15)
http://www.xdnf.cn/news/20347.html

相关文章:

  • HMI(人机界面)
  • 【基础-单选】UIAbility实例创建完成时触发的回调
  • HTML 列表类型
  • 5-8单元格区域与VS数组应用(实例:提取满足条件的数据)
  • Qt多线程编程学习
  • EG2103 SOP-8 内置600V功率MOS管 栅极驱动芯片
  • I/O 多路复用 (I/O Multiplexing)
  • 四个关于云属性的四个卫星数据集的介绍
  • 基于Spring Boot + Vue3的办公用品申领管理系统
  • 部署AIRI
  • lesson55:CSS导航组件全攻略:从基础导航条到动态三级菜单与伸缩菜单实现
  • 02.继承MonoBehaviour的单例模式基类
  • Python快速入门专业版(七):整数与浮点数:Python数值类型的运算与精度问题(附解决方案)
  • 项目中的一些比较实用的自定义控件
  • Python文件打包为EXE的工具v1.0
  • 《AI大模型应知应会100篇》第67篇 Web应用与大模型集成开发实践——1小时打造国产大模型智能客服系统
  • MySQL问题5
  • github上传步骤
  • 季度最强策略:年化247%,回撤10%,夏普比率3.79。附大小盘轮动策略python源代码。
  • Nestjs框架: 使用 CASL 库实现基于角色的权限控制(RBAC)与细粒度访问控制的实战演示
  • 【嵌入式C语言】七
  • 【IQA技术专题】 多尺度的transformer网络IQA:MUSIQ
  • GO语言的主要语法和特性
  • 跨平台游戏引擎 Axmol-2.8.1 发布
  • 突破反爬限制:动态IP轮换策略与实现
  • XXL-JOB源码分析(服务端)
  • “唐人街大赛第二届”题解
  • Spring Boot 3.x 的 @EnableAsync应用实例
  • 基于51单片机的信号发生器函数发生器设计
  • 存储卡备用区用尽,拷贝机设置坏块数量又有何意义?