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_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: aload_1
       7: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      10: istore_2
      11: 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类型。

优化策略

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981011.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯复盘记录004(2023)

涉及知识点 1.深搜 2.单调队列滑动窗口 3.位运算 4.并查集 题目 1.lanqiao3505 思路&#xff1a; dfs(index, weight, cnt) index表示瓜的索引&#xff0c; weight等于买瓜的重量&#xff0c; cnt表示买了多少瓜。 递归终止条件&#xff1a;1.如果瓜买完了&#xff0c;归…

【银河麒麟高级服务器操作系统】服务器测试业务耗时问题分析及处理全流程分享

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…

【现代深度学习技术】卷积神经网络03:填充和步幅

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…

FPGA开发,使用Deepseek V3还是R1(3):系统级与RTL级

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

【含文档+PPT+源码】基于SpringBoot和Vue的编程学习系统

项目介绍 本课程演示的是一款 基于SpringBoot和Vue的编程学习系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该…

网页复制小妙招

当你遇到网页时不能复制时&#xff0c;不要慌&#xff0c;教你一招可让你为所欲为。 平时你们在网上查找资料想复制时&#xff0c;总是会出现付费限制提示&#xff08;我也是qwq&#xff09;&#xff0c;这时不要慌&#xff0c;在空白处右击选择检查 按开检查&#xff0c;然后…

聆听PostgreSQL数据库的使用

参考&#xff1a;&#xff08;1&#xff09;零基础入门PostgreSQL教程 &#xff08;2&#xff09;菜鸟教程 文章目录 一、PostgreSQL是什么&#xff1f;二、基本使用1.下载2.操作&#xff08;1&#xff09;数据库&#xff08;2&#xff09;表 一、PostgreSQL是什么&#xff1f;…

内核进程调度队列(linux的真实调度算法) ─── linux第13课

目录 内核进程调度队列的过程 一个CPU拥有一个runqueue(运行队列在内存) 活动队列(active) 过期队列(expired) active指针和expired指针 重绘runqueue linux内核O(1)调度算法 总结 补充知识: 封装链式结构的目的是: 仅使用封装链式结构可以得到全部的task_struct的信…

【算法】手撕二分查找

目录 二分查找 【左闭右闭】/【相错终止】 【循环不变量】 【四要素】 二分查找的任意模板 【一般】情形 【左闭右闭】总结 mid的防溢出写法 【左闭右开】/【相等终止】 【一般】情形 再谈初始值 【左闭右开】总结 二分查找本质 【左开右闭】/【相等终止】 【一般…

C++入门基础知识1

今天&#xff0c;我们正式来学习C&#xff0c;由于C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助。 现在我们这篇主要是&#xff1a; 1. 补充C语言语法…

Leetcode 57-插入区间

给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 个区间的开始和结束&#xff0c;并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval [start, end] 表示另一个区间的开始和…

【三.大模型实战应用篇】【4.智能学员辅导系统:docx转PDF的自动化流程】

去年团队庆功宴上,我司CTO端着酒杯过来:“老王啊,咱们现在文档解析做得挺溜了,但老师们总抱怨下载的作业格式乱码…” 我看了眼手机里凌晨三点收到的崩溃警报,把杯里的可乐一饮而尽——得,新的副本又开了。 一、为什么PDF转换比想象中难十倍? 某次用户调研中,数学教研…

Mac上安装Pycharm

说明&#xff1a;仅供参考&#xff0c;是自己的安装流程&#xff0c;以免以后自己想不起来来看看的笔记 官网地址&#xff1a;https://www.jetbrains.com/pycharm/ 1、点击Download&#xff0c;跳转到下一个页面 2、MAC&#xff0c;选择Mac OS&#xff0c;在Pycharm Professio…

【动手学强化学习】番外2-多智能体强化学习算法框架之“MARLlib”学习

文章目录 一、待解决问题1.1 问题描述1.2 解决方法 二、方法详述2.1 必要说明2.2 应用步骤2.2.1 调研当前主流的MARL算法框架2.2.2 学习经典MARL算法框架——“MARLlib”&#xff08;1&#xff09;开发团队&#xff08;2&#xff09;简介 2.2.3 安装经典MARL算法框架——“MARL…

VPC2-多域攻击-tomcat渗透-通达oa-域控提权-密码喷射-委派攻击-数据库提权

下载链接: https://pan.baidu.com/s/1nUYj6G9ouj6BcumDgoDaGg 提取码: ejbn jishu域 windows 2008 tomcat渗透 访问发现tomcat 点击manage app 尝试弱口令进入,发现tomcat/tomcat成功进入 用哥斯拉生成后门 然后建立一个文件夹&#xff0c;把它放进去&#xff0c;把它改名…

删除链表的倒数第N个节点 力扣19

一、题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示例 3&a…

yoloV5的学习-pycharm版本

真的很让人气愤的一点&#xff0c;老师把我的pycharm给卸载了&#xff0c;我那个上面不仅有gpu-torch&#xff0c;还有gpu-torch&#xff0c;他给俺删了&#xff0c;删了很久&#xff0c;我心都碎了&#xff0c;过几天我就去找他负责&#xff0c;让他给我装回来我的环境&#x…

安防监控/视频集中存储EasyCVR视频汇聚平台如何配置AI智能分析平台的接入?

EasyCVR安防视频监控平台不仅支持AI边缘计算智能硬件设备的接入&#xff0c;还能快速集成AI智能分析平台&#xff0c;接收来自智能分析平台或设备的AI告警信息&#xff0c;如烟火检测、周界入侵检测、危险区域闯入检测、安全帽/反光衣佩戴检测等。 本文将详细介绍如何在EasyCVR…

【漫话机器学习系列】111.指数之和的对数(Log-Sum-Exp)

在计算机科学和机器学习中&#xff0c;经常会遇到计算指数和的对数的情况&#xff0c;例如&#xff1a; 然而&#xff0c;由于指数函数 的值增长极快&#xff0c;直接计算可能会导致数值上溢&#xff08;overflow&#xff09;或下溢&#xff08;underflow&#xff09;&#xf…

【决策树】分类属性的选择

文章目录 1.信息增益&#xff08;ID3&#xff09;2.信息增益率&#xff08;C4.5&#xff09;3.基尼指数&#xff08;CART&#xff09;ps.三者对比 实现决策树算法最关键的一点就是如何从所有的特征属性中选择一个最优的属性对样本进行分类&#xff0c;这种最优可以理解为希望划…