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

Java自动拆箱装箱/实例化顺序/缓存使用/原理/实例

        在 Java 编程体系中,基本数据类型与包装类紧密关联,它们各自有着独特的特性和应用场景。理解两者之间的关系,特别是涉及到拆箱与装箱、实例化顺序、区域问题、缓存问题以及效率问题。

一、为什么基本类型需要包装类

泛型与集合的需求

Java 的泛型机制要求类型参数必须是引用类型。例如,当我们创建一个ArrayList来存储整数时,如果使用基本数据类型int,编译器会报错。因为集合框架中的ArrayList、HashMap等类都需要存储对象,这就促使我们使用Integer这样的包装类。

如下示例:

// 错误示范,泛型不支持基本数据类型
// ArrayList<int> intList = new ArrayList<>(); // 正确方式,使用包装类Integer
ArrayList<Integer> integerList = new ArrayList<>(); 

面向对象编程的完整性

基本数据类型虽然简单高效,但在纯粹的面向对象编程思维中,它们显得格格不入。包装类将基本数据类型封装成对象,使其能够融入面向对象的体系中。这意味着可以像操作其他对象一样,对包装类对象进行传递、多态处理等操作,符合 Java 的面向对象编程范式。

丰富的方法支持

包装类为我们提供了大量实用的方法。以Integer类为例,toHexString(int i)方法可以将一个整数转换为十六进制字符串表示,parseInt(String s)方法则能将字符串解析为整数。这些方法极大地方便了我们对数据的处理和转换,而基本数据类型本身并不具备这样的功能。例如:

int num = 255;
String hexString = Integer.toHexString(num); // 输出 "ff"String numberStr = "123";
int parsedInt = Integer.parseInt(numberStr); // parsedInt 为 123

二、Long 或 Integer 如何比较大小

错误的比较方法

使用==

由于Long和Integer是包装类,属于对象类型。使用==比较时,比较的是对象的引用地址,而非对象所包含的值。例如:

Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println(a == b); // 输出 false,因为a和b是不同的对象引用
使用equals方法

equals方法在默认情况下也是比较对象的引用。虽然Integer和Long等包装类重写了equals方法,使其比较对象的值,但equals方法要求比较的两个对象类型必须相同。例如:

Integer intObj = 10;
Long longObj = 10L;
// 以下代码会编译错误,因为equals方法要求参数类型与调用对象类型一致
// System.out.println(intObj.equals(longObj)); 

正确的比较方法

可以先使用longValue()(对于Long类型)或intValue()(对于Integer类型)方法将包装类对象转换为基本数据类型,然后再使用==进行比较。示例如下:

Integer intA = 15;
Integer intB = 20;
boolean result = intA.intValue() == intB.intValue(); // 比较值Long longA = 100L;
Long longB = 100L;
boolean longResult = longA.longValue() == longB.longValue(); // 比较值

三、拆箱与装箱原理

装箱

装箱是将基本数据类型转换为包装类对象的过程。例如,当我们编写Integer num = 5;时,Java 编译器会自动将其转换为Integer num = Integer.valueOf(5);。Integer.valueOf方法内部有一定的逻辑,对于在特定范围内的值,会从缓存中获取对象,而不是创建新对象(后面会详细介绍缓存问题)。

拆箱

拆箱则是将包装类对象转换为基本数据类型的过程。如int value = num;,编译器会将其转换为int value = num.intValue();,即调用包装类对象的intValue方法来获取基本数据类型的值。

实例:查看反汇编文件

package org.example;public class BoxingUnboxingDemo {public static void main(String[] args) {// 自动装箱,底层执行Integer a = Integer.valueOf(10);Integer a = 10;// 自动拆箱,底层执行int b = a.intValue();int b = a;}
}

生成并查看反汇编文件,依次执行如下命令:

javac -d. org/example/BoxingUnboxingDemo.java
javap -c org.example.BoxingUnboxingDemo

输出结果如下:

Compiled from "BoxingUnboxingDemo.java"
public class org.example.BoxingUnboxingDemo {public org.example.BoxingUnboxingDemo();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: bipush        102: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;5: astore_16: aload_17: invokevirtual #3                  // Method java/lang/Integer.intValue:()I10: istore_211: return
}

从反汇编代码可以清晰地看到,Integer a = 10;这行代码被编译成了Integer a = Integer.valueOf(10);,而int b = a;被编译成了int b = a.intValue();,这就是自动装箱和拆箱在编译器层面的实现。

四、实例化顺序

package org.example;public class InstantiationOrderDemo {public static void main(String[] args) {int intValue1 = 12;Integer integerValue1 = new Integer(12);Integer integerValue2 = new Integer(34);int intValue2 = 34;System.out.println("intValue1 == integerValue1     : " + (intValue1 == integerValue1));System.out.println("intValue2 == integerValue2     : " + (intValue2 == integerValue2));}
}

在这个示例中,当基本数据类型与包装类对象使用==进行比较时,会发生自动拆箱。所以intValue1 == integerValue1和intValue2 == integerValue2实际上都是基本数据类型之间的比较,结果都为true。这表明在这种比较操作中,实例化顺序并不会影响比较结果,因为自动拆箱机制会将包装类对象转换为基本数据类型后再进行比较。

五、区域问题

基本数据类型与栈

基本数据类型(如int、double、char等)存储在栈内存中。栈内存的特点是数据存储和访问速度快,并且数据的生命周期与方法调用紧密相关。例如:

int age = 25;

这里的age变量存储在栈内存中,直接保存整数值25。当方法执行结束,age变量所占用的栈空间会被自动释放。

包装类对象与堆

包装类对象(如Integer、Double、Character等)是在堆内存中实例化的。堆内存用于存储对象,对象的生命周期由垃圾回收机制管理。当我们创建一个包装类对象时,例如:

Integer number = 10;

number变量存储在栈中,它指向堆中创建的Integer对象,该对象内部封装了int值10。自动装箱时,基本数据类型从栈转移到堆中包装类对象里;自动拆箱时,则是从堆中的包装类对象获取值并存储到栈中的基本数据类型变量中。

实例

package org.example;public class MemoryRegionDemo {public static void main(String[] args) {Integer integer1 = new Integer(12);Integer integer2 = 12;System.out.println("integer1 == integer2 : " + (integer1 == integer2));}
}

在这个例子中,integer1是通过new关键字在堆中创建的新对象,而integer2是通过自动装箱创建的对象。由于integer2的值在缓存范围内(后面会介绍缓存),它引用的是缓存中的对象。所以integer1 == integer2比较的是两个不同的对象引用,结果为false。这体现了不同的实例化方式(直接new和自动装箱)在内存区域上的差异以及对对象比较的影响。

六、缓存问题

缓存机制原理

Java 为了提高自动装箱的性能,对于部分包装类(如Integer、Byte、Short、Long、Character)实现了缓存机制。以Integer为例,其缓存范围是 -128 到 127。Integer.valueOf方法的内部逻辑如下:

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}

当进行自动装箱且值在 -128 到 127 之间时,会直接从缓存中获取对象,而不是创建新对象。

缓存的影响

示例
package org.example;public class CacheDemo {public static void main(String[] args) {Integer a = 127;Integer b = 127;Integer c = 128;Integer d = 128;System.out.println(a == b);System.out.println(c == d);}
}

执行结果为:

true

false

因为a和b的值都在缓存范围内,它们引用的是同一个缓存对象,所以a == b返回true。而c和d的值超出了缓存范围,它们是通过new Integer()创建的不同对象,所以c == d返回false。

其他包装类的缓存情况

  • Byte:由于byte的取值范围是 [-128, 127],所以相同值的Byte比较永远返回true,因为所有可能的值都在缓存范围内。
  • Short、Integer、Long:相同值在 [-128, 127] 范围内则返回true,不在此范围则返回false。
  • Character:只要char值小于等于 127,相同值比较就返回true,因为char的最小值为 0,本身就大于等于 -128。
  • Float、Double:永远返回false,因为浮点数的取值范围广泛且小数数量无限,无法进行缓存,每次装箱都会创建新对象。
  • Boolean:只有true和false两个对象,只要boolean的值相同,对应的Boolean对象就相等。

七、效率问题

装箱和拆箱的性能开销

自动装箱和拆箱虽然带来了编程的便利性,但也存在性能开销。装箱过程涉及对象的创建,包括在堆中分配内存、初始化对象等操作;拆箱过程需要调用对象的实例方法。这些操作相较于直接操作基本数据类型,效率较低。例如:

package org.example;public class PerformanceDemo {public static void main(String[] args) {long startTime = System.currentTimeMillis();Long sum = 0L;for (int i = 0; i < Integer.MAX_VALUE; i++) {sum += i;}long endTime = System.currentTimeMillis();System.out.println("使用Long类型耗时: " + (endTime - startTime) + " 毫秒");startTime = System.currentTimeMillis();long basicSum = 0L;for (int i = 0; i < Integer.MAX_VALUE; i++) {basicSum += i;}endTime = System.currentTimeMillis();System.out.println("使用long类型耗时: " + (endTime - startTime) + " 毫秒");}
}

在上述代码中,使用Long类型进行累加操作时,每次循环都会发生自动装箱和拆箱,导致性能较低。而使用基本数据类型long进行累加,直接操作基本数据,性能明显提升。实际运行结果显示,使用Long类型耗时远远大于使用long类型。

优化策略

在性能敏感的代码段中,应尽量减少不必要的装箱和拆箱操作。例如,在集合操作中,如果可以使用基本数据类型数组代替包装类对象的集合,就能够避免装箱和拆箱的开销。另外,对于需要频繁使用的小整数,可以利用缓存机制,确保值在缓存范围内,以提高效率。比如在循环中需要频繁使用固定范围内的整数时,提前将这些整数装箱并缓存起来,避免重复装箱操作。

相关文章:

Java自动拆箱装箱/实例化顺序/缓存使用/原理/实例

在 Java 编程体系中&#xff0c;基本数据类型与包装类紧密关联&#xff0c;它们各自有着独特的特性和应用场景。理解两者之间的关系&#xff0c;特别是涉及到拆箱与装箱、实例化顺序、区域问题、缓存问题以及效率问题。 一、为什么基本类型需要包装类 泛型与集合的需求 Java…...

软件工程---基于构件的软件工程

基于构件的软件工程&#xff08;CBSE&#xff09;是一种软件开发方法&#xff0c;通过重用现有的软件构件来构建系统&#xff0c;从而提高开发效率和软件质量。这种方法强调软件系统的模块化设计和构建复用&#xff0c;使得软件开发过程更加高效和灵活。 企业软件开发&#xf…...

AMD RDNA3 GPU架构解析

本文会通过把AMD的RDNA3架构为例比喻为**“施工公司”**工作模式&#xff0c;深入理解GPU如何高效处理顶点着色、像素计算等任务。 一、施工公司的组织架构 1. 施工公司&#xff08;WGP&#xff09;与施工队&#xff08;CU&#xff09; WGP&#xff08;Work Group Processor&…...

docker关闭mysql端口映射的使用

需求 项目中的数据库为mysql&#xff0c;如果将端口映射到宿主机上&#xff0c;容易被工具扫描出&#xff0c;且随着国产化的进程推进&#xff0c;mysql将不被允许。为了提高安全性与满足项目需求&#xff0c;这里采用隐藏mysql端口方式&#xff0c;不映射宿主机端口&#xff…...

关于对机器中的人工智能进行基准测试

大家读完觉得有帮助记得及时关注和点赞&#xff01;&#xff01;&#xff01; 抽象 最近的基准研究声称&#xff0c;AI 在各种认知任务上的表现已经接近甚至超过人类的“水平”。然而&#xff0c;本立场文件认为&#xff0c;当前的 AI 评估范式不足以评估类似人类的认知能力。我…...

CSS - 妙用Sass

官方文档&#xff1a;https://www.sass.hk/docs/ 1.例1&#xff1a; each $theme in $themeList {$themeKey: map-get($theme, key);media screen and (weex-theme: $themeKey) {.btnText {max-width: 150px;include font(map-get($theme, medFont),map-get($theme, subFontS…...

MS模块创新

1. 动态分支权重融合 创新思路&#xff1a;引入通道注意力机制&#xff0c;自动学习高频/低频分支的融合权重 class DynamicMS(nn.Module):def __init__(self, in_channels1):super().__init__()# 原高频/低频分支保持不变self.high_freq ... # 与原MS模块相同self.low_freq…...

私有化部署DeepSeek并SpringBoot集成使用(附UI界面使用教程-支持语音、图片)

私有化部署DeepSeek并SpringBoot集成使用&#xff08;附UI界面使用教程-支持语音、图片&#xff09; windows部署ollama Ollama 是一个开源框架&#xff0c;专为在本地机器上便捷部署和运行大型语言模型&#xff08;LLM&#xff09;而设计 下载ollama 下载地址&#xff08;…...

MFC中CMutex类和CSingleLock类,配合使用疑惑

在使用CMutex过程中&#xff0c;看到别人使用了CSingleLock类&#xff0c;想着明明CMutex已经可以实现线程同步了&#xff0c;为什么还有使用CSingleLock类呢&#xff1f; 在MFC中&#xff0c;虽然CMutex类本身可以实现线程同步&#xff0c;但通常会与CSingleLock类一起使用&am…...

残差收缩模块

1. 多尺度阈值生成 创新思路&#xff1a;融合不同尺度的统计信息&#xff08;如平均池化最大池化&#xff09;生成更鲁棒的阈值。 class MultiScaleShrinkage(nn.Module):def __init__(self, channel, reduction4):super().__init__()# 多尺度池化分支self.avg_pool nn.Adap…...

HOW - 在Windows浏览器中模拟MacOS的滚动条

目录 一、原生 CSS 代码实现模拟 macOS 滚动条额外优化应用到某个特定容器 二、Antd table中的滚动条场景三、使用第三方工具/扩展 如果你想让 Windows 里的滚动条 模拟 macOS 的效果&#xff08;细窄、圆角、隐藏默认轨道&#xff09;。 可以使用以下几种方案&#xff1a; 一…...

Unity 打包后EXE运行出现Field to Load il2cpp的一种情况

Unity版本2021.3.13f1c1 #if DEVELOPMENT_BUILDA1 A1 10600;#else#endif 使用 #if DEVELOPMENT_BUILD然后在下面面板使用Development Build。打包后会运行游戏EXE出现Field to Load il2cpp。 解决办法是换成IF ELSE&#xff0c;自己代码设置个开关、 文心一言&#xff1a; …...

Windows 环境下 Nginx、PHP 与 ThinkPHP 开发环境搭建

Windows 环境下 Nginx、PHP 与 ThinkPHP 开发环境搭建 目录 安装 Nginx 和 PHP配置 Nginx配置 PHP启动服务ThinkPHP 配置常见问题排查 1. 安装 Nginx 和 PHP 安装 Nginx 访问 Nginx 官网 下载 Windows 版本解压到指定目录&#xff0c;如 C:\nginx 安装 PHP 访问 PHP 官网…...

Redis100道高频面试题

一、Redis基础 Redis是什么&#xff1f;主要应用场景有哪些&#xff1f; Redis 是一个开源的、基于内存的数据结构存储系统&#xff0c;支持多种数据结构&#xff08;如字符串、哈希、列表、集合等&#xff09;&#xff0c;可以用作数据库、缓存和消息中间件。 主要应用场景&…...

登录服务器后如何找到对应的drupal所在的文件夹

在服务器上找不到 Drupal 安装目录的原因可能有以下几种&#xff1a; 多站点配置&#xff1a; Drupal 支持多站点设置&#xff0c;即在同一安装中托管多个网站。在这种配置下&#xff0c;每个站点都有自己的设置和文件夹&#xff0c;通常位于 sites 目录下。例如&#xff0c;站…...

win32汇编环境,窗口程序中使控件子类化的示例一

;运行效果 ;win32汇编环境,窗口程序中使编辑框控件子类化的示例一 ;窗口子类化&#xff0c;就是把某种控件&#xff0c;自已再打造一遍&#xff0c;加入自已的功能。比如弄个特殊形状的按钮&#xff0c;或只能输入特殊字符的编辑框 ;当然&#xff0c;一般来说&#xff0c;这都是…...

专业工具,杜绝一切垃圾残留!

在安装大多数软件时均会在系统注册表中创建相应的条目。如果卸载后仍然存在注册表残留&#xff0c;可能会导致再次安装时出现失败&#xff0c;同时也会对系统性能和存储空间产生负面影响。常见的卸载残留包括注册表项、程序文件夹、用户数据文件夹、临时文件以及相关插件等。 …...

java 实现简易基于Dledger 的选举

java 实现简易基于Dledger 的选举 1. 定义 Dledger 节点类&#xff0c;包含节点的状态、日志存储、选举和日志复制逻辑 import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.S…...

大数据“调味“ ,智慧“添香“,看永洪科技助力绝味食品数字化新征程

近年来&#xff0c;随着国家数字化政策不断出台、新兴技术不断进步、企业内生需求持续释放&#xff0c;数字化转型逐步成为企业实现高质量发展的必由之路&#xff0c;成为企业实现可持续发展乃至弯道超车的重要途径。 在全国数字化浪潮驱动下&#xff0c;以人工智能、互联网、…...

【嵌入式】MQTT

MQTT 文章目录 MQTT安装简介MQTT客户端代码 安装 安装Paho MQTT C库: sudo apt-get install libpaho-mqtt3-dev头文件包含&#xff1a; #include "MQTTClient.h"编译选项&#xff1a; gcc -o $ $^ -lpaho-mqtt3c简介 MQTT协议全称是&#xff08;Message Queuing…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...