Java的包装类和自动拆装箱

一、引言

想必有相当一部分人听说过这么一个笑话:

Java程序员刘老六和柳老流在一块吐苦水,刘老六说,我这当了这么多年程序员,怎么就找不到一个女朋友呢,家里老催我找对象呢,这个柳老流就安慰他说,没关系啊,你可以 new 一个对象。

 在Java中,万物皆对象。那么什么是对象呢?

有解释为:对象是类的实例化。以内存的角度来说,对象是堆中的一块内存空间。

那么Java中有两大类数据类型,一种是基本数据类型,一种是引用数据类型。基本数据类型不能创建对象啊,这不是与万物皆对象的思想不一致了吗?

二、包装类

基本数据类型经常被用于简单的计算和数据存储,然而有时我们需要将这些基本类型存储为对象来进行更复杂的操作,或者在泛型类(如:ArrayList)中使用数据。由此,Java万物皆对象的思想在基本数据类型上仍有体现。

1、什么是包装类

包装类是基本数据类型的对象表示。每个基本类型都有对应的包装类

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
doubleDouble
floatFloat
charCharacter
booleanBoolean

包装类的主要作用是将基本数据类型转换为对象,或者将对象转换回基本数据类型。这对于需要对象而不能直接使用基本类型的情况非常有用。如:在ArrayList等集合类中,我们不能直接存储基本数据类型,只能存储对象,而包装类正好提供了这一功能。

Byte b1 = null;  //  √
byte b2 = null;  //  ×

 包装类本质都是类,可以赋值为null,但是基本类型不可赋值为null。

2、包装类的特性

1. 不可变

一旦构造了包装器,就不允许更改包装在其中的值。

Integer x = 10;
x = 20;  // 创建了一个新的Integer对象,原来的x对象不能改变

2. final修饰

包装类由final修饰,不可定义它们的子类。

3. 数字型包装类共同超类Number

Byte、Short、Integer、Long、Float、Double等六个包装类有共同的父类Number。

4. 提供常量

包装类提供了几个常量,这些常量通常是该类型的最大值、最小值等。可以通过这些常量来方便地获取数值范围。

System.out.println("最大值: " + Integer.MAX_VALUE);  // 2147483647
System.out.println("最小值: " + Integer.MIN_VALUE);  // -2147483648
System.out.println("True: " + Boolean.TRUE);         // true
System.out.println("False: " + Boolean.FALSE);       // false

5. 包装类和对应基本类型可以互相转换

每个包装类都提供了将其值转换为对应基本数据类型的方法。这些方法通常以intValue()、doubleValue()、booleanValue()等形式命名。

Integer integerObj = Integer.valueOf(100);
int num = integerObj.intValue();  // 转换为基本类型 int
System.out.println("转换后的值: " + num);

可以使用 valueOf()方法将一个基本数据类型转换为对应的包装类对象。

int num = 10;
Integer integerObj = Integer.valueOf(num);  // 将int转换为Integer对象
System.out.println("包装类对象: " + integerObj);

6. 静态方法: valueOf() 和 parseXXX() 

valueOf() 方法用于将基本数据类型转换为包装类对象,或者将字符串转换为包装类对象。

Integer x = Integer.valueOf(42);  // 从int转换为Integer
Integer y = Integer.valueOf("42"); // 从String转换为Integer

parseXXX()  方法用于将字符串转换为基本数据类型。

int x = Integer.parseInt("42");    // 从String转换为int
double y = Double.parseDouble("3.14"); // 从String转换为double

7. 实现了Comparable接口

所有的包装类都实现了Comparable接口。可以比较包装类对象的大小。

Integer a = 10;
Integer b = 20;
int comparisonResult = a.compareTo(b);  // 比较a和b
System.out.println("比较结果: " + comparisonResult);  // 输出负数,因为10小于20

8. 自动拆装箱

基本数据类型和包装类之间的转换可以自动进行,Java会在需要时自动将基本数据类型转换为对应的包装类对象(装箱),或者将包装类对象转换为基本数据类型(拆箱)。

ArrayList<Integer> list = new ArrayList<>();
list.add(10);  // 自动装箱,将int 10 转换为 Integer 对象
int num = list.get(0);  // 自动拆箱,将 Integer 对象转换为 int
System.out.println("Number: " + num);

9. 重写了 hashCode() 和 equals() 

包装类重写了 hashCode() 和 equals() ,以便进行对象比较。equals() 方法用于比较对象的值,hashCode()用于计算对象的哈希值。

Integer x = 10;
Integer y = 10;
System.out.println(x.equals(y));  // 输出 true,因为两个Integer对象的值相同
System.out.println(x.hashCode()); // 输出 10 的哈希值

包装类使用的是值的比较,而不是对象的内存地址比较。

10. 线程安全

包装类对象是不可变的,这意味着它们是线程安全的。在多线程环境中,多个线程共享包装类对象时,不会出现并发修改的问题。

三、128陷阱

1、什么是“128陷阱”

包装类采用了缓存机制来优化内存使用和性能。这一机制可能会导致一些看似矛盾的行为,通常被称为“128陷阱”。

对于数值型包装类,如果数值一样但是不在-128~127之间,则不是同一个对象。

对于Char、Boolean、Byte,需要 ≤ 127

这个范围的使用频率比较高,同一个变量指向同一个对象,会节省内存。

Integet a1 = 100;
Integet a2 = 100;
System.out.println(a1==a2); // true

Integet a3 = 200;
Integet a4 = 200;
System.out.println(a3==a4); // false

 2、从源码理解“128陷阱”

以Integer为例,上源码

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

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

    private final int value;

    public Integer(int value) {
        this.value = value;
    }

 由Integer类源码可以发现,Integer类对-128到127范围内的整数进行缓存,缓存到一个长为256数组中内,当创建值在该范围内的一个Integer对象,直接引用缓存中的数据,即引用了同一块内存地址,使用==操作符比较两个对象是返回true。

当创建一个值不在该范围内的Integer对象,Java不会使用缓存,而是创建新对象,这样即使两个Integer的值相同,引用也会不同,==操作符比较时会返回false。

四、自动拆装箱

自动拆装箱简化了基本数据类型和其包装类之间的转换。通过这两种机制,Java能够在不显式调用转换方法的情况下,自动进行这些转换操作。

1、自动装箱

自动装箱是指,Java会自动基本数据类型转换为相应的包装类对象

int a = 10;
        
// 自动装箱:将int类型的a装箱为Integer对象
Integer integerObj = a; // 相当于 Integer.valueOf(a);
        
System.out.println("integerObj: " + integerObj);  // 输出 Integer对象

2、自动拆箱

自动拆箱是指,Java会自动包装类对象转换为相应的基本数据类型

Integer integerObj = 10;  // 自动装箱
int a = integerObj;       // 自动拆箱:将Integer对象转换为基本数据类型int
        
System.out.println("a: " + a);  // 输出基本数据类型 int 值

3、自动装箱和自动拆箱的发生时机

1. 自动装箱

(1)将基本数据类型赋值给包装类对象

Integer integerObj = 100;  // 自动装箱:int 100 被装箱成 Integer 对象

(2)将基本数据类型传递给需要对象的集合或方法

List<Integer> list = new ArrayList<>();
list.add(10);  // 自动装箱:将 int 10 转换为 Integer 对象并添加到 List 中

2. 自动拆箱

(1)将包装类对象赋值给基本数据类型变量

Integer integerObj = 10;
int a = integerObj;  // 自动拆箱:将 Integer 对象转换为 int 类型

(2)将包装类对象传递给要求基本数据类型的集合或方法

Integer integerObj = 20;
int result = integerObj + 10;  // 自动拆箱:将 Integer 对象拆箱为 int 后进行加法运算

3. 混合使用

自动装箱与自动拆箱是同时发生的。“+”运算符会触发自动拆箱,然后将拆箱后的值与10相加,再将结果装箱成 Integer对象。

Integer a = 100;

Integer b = 200;

// 自动拆箱和装箱混合:a和b会被自动拆箱为int类型,运算结果会被装箱为Integer

Integer sum = a + b;  // 自动拆箱:a和b被拆箱为int,再加法运算,结果会自动装箱为Integer

System.out.println("Sum: " + sum);  // 输出 300

4. 例子

        int a = 10;
		int b = 10;
		Integer a1 =10;
		Integer b1 = 10;
		Integer a2 = new Integer(10);
		Integer b2 = new Integer(10);
		
		System.out.println(a==b); // true ,不涉及拆装箱
		System.out.println(a1==b1); // true ,不涉及拆装箱
		System.out.println(a2==b2); // false ,不涉及拆装箱
		System.out.println(a1==a); // true ,a1拆箱比较值
		System.out.println(a1.equals(a)); // true ,a1拆箱比较值
		System.out.println(a1==a2); // false,不涉及拆装箱
		System.out.println(a==a2); // true ,a2拆箱比较值

解释System.out.println(a1.equals(a)); // true

a1 是 Integer 类型 的,a是 int 类型的,判断的时候 Integer 要转出为 int 来判断,进行了自动拆箱。此处的equals方法在Integer中重写了,底层还是使用==来判断

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

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

相关文章

网络安全尹毅 《网络安全》

一 网络安全基本概念 1.网络安全定义 安全在字典中的定义是为了防范间谍活动或蓄意破坏、犯罪、攻击而采取的措施。网络安全就是为了防范计算机网络硬件、软件、数据被偶然或蓄意破坏、篡改、窃听、假冒、泄露、非法访问以及保护网络系统持续有效工作的措施总和。网络安全保护…

6.appender

文章目录 一、前言二、源码解析AppenderUnsynchronizedAppenderBaseOutputStreamAppenderConsoleAppenderFileAppenderRollingFileAppenderFileNamePattern 三、总结 一、前言 前一篇文章介绍了appender、conversionRule、root和logger节点的解析, 为的是为本篇详细介绍它们的…

P9584 「MXOI Round 1」城市

题目描述 小 C 是 F 国的总统&#xff0c;尽管这个国家仅存在于网络游戏中&#xff0c;但他确实是这个国家的总统。 F 国由 n 个城市构成&#xff0c;这 n 个城市之间由 n−1 条双向道路互相连接。保证从任意一个城市出发&#xff0c;都能通过这 n−1 条双向道路&#xff0c;…

什么是Docker多架构容器镜像

什么是Docker多架构容器镜像 在 Docker 中&#xff0c;同一个 Docker 镜像可以在不同的平台上运行&#xff0c;例如在 x86、ARM、PowerPC 等不同的 CPU 架构上。 为了支持这种多平台的镜像构建和管理&#xff0c;Docker 在 17.06 版本时引入了 Manifest 的概念&#xff0c;在…

Baklib知识中台构建企业智能运营核心架构

内容概要 在数字化转型的浪潮中&#xff0c;企业对于知识的系统化管理需求日益迫切。Baklib作为新一代的知识中台&#xff0c;通过构建智能运营核心架构&#xff0c;为企业提供了一套从知识汇聚到场景化落地的完整解决方案。其核心价值在于将分散的知识资源整合为统一的资产池…

深度学习机器学习:常用激活函数(activation function)详解

目录 Sigmoid Function ReLU&#xff08;Rectified Linear Unit&#xff09; LeakyReLU&#xff08;Leaky Rectified Linear Unit&#xff09; ClippedReLU&#xff08;Clipped Rectified Linear Unit&#xff09; PRelu&#xff08;Parametric ReLU&#xff09; Tanh&am…

【面试】网络安全常问150道面试题

1&#xff0c;拿到一个待测网站&#xff0c;你觉得应该先做什么&#xff1f; 信息收集&#xff1a; 服务器相关---&#xff1a;## 系统版本&#xff0c;真实IP&#xff0c;开放端口&#xff0c;使用的中间件 指纹信息---## 有无cdn加速&#xff0c;dns解析记录&#xff0c;是不…

【Linux】--- 基础开发工具之yum/apt、vim、gcc/g++的使用

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; Linux网络编程 本篇博客我们来认识一下Linux中的一些基础开发工具 --- yum,vim,gcc/g。 &#x1f3e0; yum &#x1f3b8; 什么是yum 当用户想下载软…

物联网平台-分布式的设备接入与管理系统

乐吾乐物联网平台是由乐吾乐自主研发的一款分布式的设备接入与管理系统&#xff0c;专为满足不断增长的设备接入和数据处理需求而设计。平台集数据采集、分析、监控、告警和通知等功能于一体&#xff0c;并融合了乐吾乐大屏可视化和乐吾乐3D数字孪生技术&#xff0c;帮助用户快…

Day65_20250213图论part9_dijkstra(堆优化版)|Bellman_ford算法精讲

Day65_20250213图论part9_dijkstra(堆优化版)|Bellman_ford算法精讲 dijkstra(堆优化版) 题目 https://www.programmercarl.com/kamacoder/0047.%E5%8F%82%E4%BC%9Adijkstra%E5%A0%86.html 小明参加科学大会 思路 思路 朴素版的dijkstra&#xff0c;时间复杂度为O(n^2)&am…

动手实现自己的 JVM——Go!(ch01)

动手实现自己的 JVM——Go&#xff01;&#xff08;ch01&#xff09; 参考张秀宏老师的《自己动手写java虚拟机》 为什么需要命令行 在 JMV 中&#xff0c;要运行一个 Java 文件&#xff08;字节码&#xff09;&#xff0c;首先需要找到这个文件。那么&#xff0c;如何找到文件…

IIS部署netcore程序后,出现500.30错误解决方案之一

netcore程序部署到IIS后一直出现错误&#xff0c;访问首页后会跳转到登录页地址&#xff0c;然后看到如下错误 HTTP Error 500.30 - ANCM In-Process Start Failure Common solutions to this issue: The application failed to start The application started but then stopp…

将Docker容器打包成镜像提交

前言 Docker 是一个开源软件&#xff0c;也是一个开放平台&#xff0c;用于开发应用、交付&#xff08;shipping&#xff09;应用、运行应用。 Docker允许用户将基础设施&#xff08;Infrastructure&#xff09;中的应用单独分割出来&#xff0c;形成更小的颗粒&#xff08;容…

【设计模式】【行为型模式】命令模式(Command)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f3b5; 当你的天空突…

【DDD系列-3】DDD战术设计实践分享

DDD 战术设计概念​ ​ ​​ TMF2 中的概念&#xff1a;​ 领域能力&#xff1a;​ 扩展点&#xff1a;​ DDD 战术设计使用场景​ 复杂业务场景​ 复杂来源面对的需求方更加多样化。​ 1 相同场景不同垂直业务方的需求&#xff08;1688&#xff0c;淘宝&#xff0c;天…

基于单片机的仓库安防系统(论文+源码)

2.1 需求分析 仓库由于存有大量物品&#xff0c;因此对仓库的监控非常重要&#xff0c;目前仓库已经普遍装有安防系统&#xff0c;以保证仓库的安全&#xff0c;本次基于单片机的仓库安防系统设计&#xff0c;在功能上设计如下&#xff1a; 用户可通过IC卡进入仓库&#xff1…

使用 AutoMQ 和 Tinybird 分析用户网购行为

前言 在当前竞争激烈的市场环境中&#xff0c;数据分析已成为企业实现差异化和精准营销的关键。通过分析用户行为数据&#xff0c;企业能够深入了解用户的习惯、偏好和行为模式&#xff0c;从而更精准地定位目标市场&#xff0c;制定个性化营销策略&#xff0c;并提供定制化推…

小米 R3G 路由器刷机教程(Pandavan)

小米 R3G 路由器刷机教程&#xff08;Pandavan&#xff09; 一、前言 小米 R3G 路由器以其高性价比和稳定的性能备受用户青睐。然而&#xff0c;原厂固件的功能相对有限&#xff0c;难以满足高级用户的个性化需求。刷机不仅可以解锁路由器的潜能&#xff0c;还能通过第三方固…

Python数据可视化 - Matplotlib教程

文章目录 前言一、Matplotlib简介及安装1. Matplotlib简介2. 安装Matplotlib 二、Matplotlib Pyplot1. Pyplot介绍2. Pyplot中方法介绍2.1 创建和管理图形2.2 绘制图形2.3 设置图形属性2.4 保存和展示 三、Matplotlib绘图标记1. 介绍2. 基本用法3. 标记大小与颜色4. 标记样式列…

DeepSeek 与网络安全:AI 驱动的智能防御

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;深度学习技术正渗透到多个领域&#xff0c;从医疗诊断到…