java知识点---装箱拆箱

2024-04-22 17:36
文章标签 java 知识点 装箱 拆箱

本文主要是介绍java知识点---装箱拆箱,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在Java中,装箱拆箱是指基本数据类型(也称为值类型)与它们对应的包装器类(引用类型)之间相互转换的过程。

装箱(Boxing)

装箱是指将基本数据类型(如 intdoubleboolean 等)的值转换为相应包装器类(如 IntegerDoubleBoolean 等)的实例对象的过程。这样做的主要目的是为了让基本类型能够参与那些只能由对象实现的操作,如存储在集合类(如 ArrayListHashMap)中、作为泛型类型参数、传递给期望接收对象参数的方法等。

装箱方式

  1. 自动装箱:自Java 5(JDK 1.5)开始,编译器会自动将基本类型值转换为相应的包装器类型对象。例如:

    int primitiveValue = 42;
    Integer wrapperObject = primitiveValue; // 自动装箱
    

    在这里,编译器会隐式调用 Integer.valueOf(primitiveValue) 来创建 Integer 实例。

  2. 手动装箱:在Java 5之前或需要明确控制装箱过程时,可以通过调用包装器类的构造函数或静态工厂方法(如 valueOf())来实现装箱:

    int primitiveValue = 42;
    Integer wrapperObject = new Integer(primitiveValue); // 手动装箱
    

拆箱(Unboxing)

拆箱则是相反的过程,即将包装器类对象转换回其对应的基本数据类型值。拆箱通常发生在需要使用基本类型值的场景,如进行算术运算、比较操作、赋值给基本类型变量等。

拆箱方式

  1. 自动拆箱:同样自Java 5起,编译器也会自动将包装器类型对象转换为基本类型值。例如:

    Integer wrapperObject = 42;
    int primitiveValue = wrapperObject; // 自动拆箱
    

    此处,编译器实际上执行了 wrapperObject.intValue() 来获取 int 值。

  2. 手动拆箱:在需要显式控制拆箱时,可以直接调用包装器对象的 xxxValue() 方法(其中 xxx 表示对应的基本类型,如 intValue()doubleValue()booleanValue() 等):

    Integer wrapperObject = 42;
    int primitiveValue = wrapperObject.intValue(); // 手动拆箱
    

注意事项

  • 性能影响:虽然装箱和拆箱操作对开发人员来说通常是透明的,但它们并非无成本。每次装箱都会创建一个新的对象,而拆箱则涉及对象方法调用。在大量进行这种转换的场景下,可能会导致额外的内存消耗和性能开销。因此,对于性能敏感的代码段,应尽量避免不必要的装箱和拆箱。

  • 空指针异常:在进行自动或手动拆箱时,如果包装器对象为 null,将会抛出 NullPointerException。因此,使用包装器类型时需注意处理可能的 null 值。

  • 常量池优化:对于某些范围内的整数,Java编译器和运行时会对自动装箱进行优化,通过缓存和重用已创建的包装器对象,而不是每次都新建。例如,Integer 对象在 -128127 的范围内会采用缓存策略。

除了创建 ByteShort 对象时可能需要显式类型转换外,在使用包装类型时还应注意以下几点:

空对象与空指针异常

包装器类型是对象,因此它们可以为 null。在进行拆箱操作(从包装类型到原始类型)时,如果包装器对象为 null,会抛出 NullPointerException。在使用包装类型时,尤其是进行拆箱操作前,要确保对象非空,或者做好适当的异常处理。

Integer i = null;
int value = i; // 这将抛出 NullPointerException

自动装箱与常量池优化

Java 5(JDK 1.5)引入了自动装箱功能,编译器会自动将原始类型值转换为对应的包装器对象。对于 IntegerLongShortByteCharacterBoolean,如果它们的值在特定范围内(如 Integer-128127),Java会使用常量池缓存这些对象,避免重复创建。这意味着对于这些范围内的值,自动装箱后的对象实际上是同一个对象,可以使用 == 进行比较。

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // 输出 true,因为它们指向常量池中的同一个对象

对于超出常量池范围的值,每次装箱都会创建新的对象,此时应使用 equals() 方法进行值的比较。

与基本类型比较

在进行条件判断、循环控制等逻辑操作时,如果直接比较包装类型对象,编译器会自动进行拆箱操作。但在编写代码时,为了提高可读性,建议显式地使用 .equals() 方法进行对象间的值比较,或者使用 .compareTo() 方法进行有顺序的比较。

Integer x = 10;
Integer y = 20;if (x < y) { // 自动拆箱后进行比较,正确...
}// 更推荐的方式
if (x.compareTo(y) < 0) {...
}

使用 equals() 方法而非 ==

在比较包装类型对象时,通常应使用 equals() 方法而非 == 运算符。== 用于比较两个对象的引用是否指向同一块内存地址,而 equals() 方法用于比较对象的内容是否相等。只有在进行常量池优化范围内的值比较,或者明确知道两个对象引用指向同一对象时,才适合使用 ==

Integer a = new Integer(10);
Integer b = new Integer(10);System.out.println(a == b); // 输出 false,因为它们是两个独立的对象
System.out.println(a.equals(b)); // 输出 true,因为它们的值相等

避免不必要的装箱与拆箱

装箱和拆箱操作虽然方便,但会产生额外的性能开销。在性能敏感的代码中,应尽量避免不必要的装箱和拆箱。例如,如果一个方法只需要处理原始类型值,那么其参数和返回值应声明为原始类型,而不是包装类型。

// 避免不必要的装箱
void processIntegers(int[] values) {for (int value : values) {// ...}
}// 避免不必要的拆箱
int sum(Integer[] values) {int sum = 0;for (Integer value : values) {sum += value; // 自动拆箱}return sum;
}

综上所述,使用包装类型时应关注空对象处理、常量池优化、比较操作的正确性、以及避免不必要的装箱与拆箱,以确保代码的健壮性、可读性和高效性。

综上所述,Java中的装箱和拆箱机制使得基本类型能够与对象无缝交互,增强了语言的表达能力和代码的通用性,但同时也需要注意潜在的性能问题和空指针异常风险。在编写代码时应合理运用,并在必要时采取优化措施。

在Java中,当你创建一个对象时,通常会使用构造函数来初始化。对于像 ByteShort 这样的包装器类,它们的构造函数接受各自对应的原始类型(byteshort)作为参数。在创建这些对象时,之所以有时候需要显式地添加 (byte)(short) 类型转换,主要是为了避免由于编译器的类型推断规则导致的隐式类型提升。

类型提升规则

在Java中,当一个较小的整数类型(如 byteshort)与一个较大的整数类型(如 intlong)进行混合运算或赋值时,按照Java的类型提升规则,较小的类型会被自动提升至较大的类型,以确保运算的一致性和安全性。具体来说:

  • 当一个 byteshort 参与运算时,它会被提升至 int 类型。
  • 如果一个 char 参与运算,它也会被提升至 int 类型。

这是因为在Java中,int 是最常用的整数类型,且大多数处理器对其支持得非常好。因此,为了提高效率和简化设计,Java标准规定了这样的自动类型提升。

创建 ByteShort 对象的情况

在创建 ByteShort 对象时,如果直接使用一个字面值(如 123),这个字面值默认会被解释为 int 类型。例如:

Byte b = new Byte(123);  // 编译错误
Short s = new Short(456);  // 编译错误

上述代码会引发编译错误,因为 ByteShort 的构造函数期望的是 byteshort 类型的参数,而提供的 int 类型字面值并不匹配。

为了解决这个问题,需要显式地进行类型转换,告诉编译器你希望将这个字面值当作 byteshort 类型来处理:

Byte b = new Byte((byte) 123);  // 正确
Short s = new Short((short) 456);  // 正确

这里的 (byte)(short) 是类型转换操作符,它们确保了传递给构造函数的参数是预期的小整数类型,而不是被提升为 int 类型的字面值。

例外情况

然而,如果你直接使用符合 byteshort 范围的字面值(即,对于 byte,其值在 -128127 之间;对于 short,其值在 -3276832767 之间),编译器能够识别这样的字面值并将其视为对应的小整数类型,这时就不需要显式类型转换:

Byte b = new Byte(100);  // 正确,因为 100 在 byte 的范围内
Short s = new Short(32767);  // 正确,因为 32767 在 short 的范围内

总之,创建 ByteShort 对象时,如果提供的字面值超出了它们的自然范围(即 byte-128127,或 short-3276832767),或者为了确保代码的清晰性和防止隐式类型提升带来的混淆,就需要使用 (byte)(short) 显式类型转换。在其他情况下,如果字面值本身就在目标类型的范围内,编译器可以正确推断类型,无需额外的类型转换。

这篇关于java知识点---装箱拆箱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/926423

相关文章

嵌入式软件工程师应聘知识点

嵌入式软件工程师应聘 修改浏览权限 | 删除 数据结构(C语言)部分常考的知识点: 1、局部变量能、全局变量和静态变量 2、堆和栈 3、Const、volatile、define、typedef的用途 4、链表(比如链表的插入、删除和排序) 5、排序(考查冒泡法的较多) 6、可重入函数 、malloc函数 7、指针(常考函数指针,函数指针,数组指针,指针数组和

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

Java面试题:通过实例说明内连接、左外连接和右外连接的区别

在 SQL 中,连接(JOIN)用于在多个表之间组合行。最常用的连接类型是内连接(INNER JOIN)、左外连接(LEFT OUTER JOIN)和右外连接(RIGHT OUTER JOIN)。它们的主要区别在于它们如何处理表之间的匹配和不匹配行。下面是每种连接的详细说明和示例。 表示例 假设有两个表:Customers 和 Orders。 Customers CustomerIDCus