【✅Java中有了基本类型为什么还需要包装类?】

在这里插入图片描述

✅Java中有了基本类型为什么还需要包装类?

  • ✅Java中有了基本类型为什么还需要包装类
    • ✅Java的8中基本数据类型
  • ✅知识拓展
    • ✅基本类型和包装类型的区别
    • ✅如何理解自动拆装箱?
      • ✅拆箱与装箱
      • ✅自动拆装箱
      • ✅自动拆装箱原理
    • ✅哪些地方会自动拆装箱?
      • 🍁场景一:将基本数据类型放入集合类
      • 🍁场景二:包装类型和基本类型的大小比较
      • 🍁场景三:包装类型的运算
      • 🍁场景四:三目运算符的使用
      • 🍁场景五:函数参数与返回值
    • ✅自动拆装箱与缓存

✅Java中有了基本类型为什么还需要包装类

✅Java的8中基本数据类型

Java中的8中基本数据类型,这些基本类型又都有对应的包装类。看一下表格:

数据类型分类描述取值范围示例包装类对应长度
byte整数类型8位有符号二进制整数-128 到 127byte a = -50;Byte1字节
short整数类型16位有符号二进制整数-32768 到 32767short b = 10000;Short2字节
int整数类型32位有符号二进制整数-2^31 到 2^31-1int c = -20000;Integer4字节
long整数类型64位有符号二进制整数-2^63 到 2^63-1long d = 1000000000L;Long8字节
float小数类型单精度浮点数(32位IEEE 754)由IEEE 754标准定义,约±3.4E±38Ffloat e = 3.14f;Float4字节(IEEE 754单精度浮点数)
double小数类型双精度浮点数(64位IEEE 754)由IEEE 754标准定义,约±1.7E±308Ddouble f = 2.71828D;Double8字节(IEEE 754双精度浮点数)
char字符类型16位Unicode字符(UTF-16编码)U+0000 到 U+FFFF(包括Unicode字符和特殊字符)char g = ‘A’; char h = ‘\u0041’;Character2字节(UTF-16编码)
boolean布尔类型布尔类型,只能取两个值:true和falsetrue 或 falseboolean i = true; boolean j = false;Boolean-(布尔类型的长度不固定)

因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int、double等类型放进去的。因为集合的容器要求元素是Obiect类型。


为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,主富了基本类型的操作。

✅知识拓展

✅基本类型和包装类型的区别

基本类型和包装类型在Java中有着明显的区别。以下是一些主要的差异:

基本类型

  • 它们是简单的数据类型,用于存储基础值,如整数、浮点数、字符等。
  • 它们的值直接存储,不包含任何额外的信息。
  • 它们是原始数据类型,没有方法,只有一些预定义的操作。

包装类型:

  • 包装类型是基本类型的类表示。
  • 包装类型提供了对基本类型的封装,可以防止数据的直接访问和修改。
  • 包装类型可以包含方法,扩展了基本类型的功能。

总而言之:
1.默认值不同,基本类型的默认值为0,false或 u0000等,包装类默认为null
2.初始化方式不同,一个需要new,一个不需要
3.存储方式不同,基本类型保存在栈上,包装类对象保存在堆上(成员变量的话,在不考虑川T优化的栈上分配时,都是随着对象一起保存在堆上的)

public class DataTypeMain {  
    public static void main(String[] args) {  
        // 基本类型  
        int basicInt = 10;  
        System.out.println("基本类型的值: " + basicInt);  
          
        // 包装类型  
        Integer wrappedInt = new Integer(10);  
        System.out.println("包装类型的值: " + wrappedInt);  
          
        // 包装类型的方法  
        wrappedInt = wrappedInt + 5; // 使用包装类型的加法方法  
        System.out.println("包装类型的新值: " + wrappedInt);  
          
        // 基本类型不能直接进行加法操作,需要手动转换包装类型为基本类型,再执行加法操作  
        basicInt = basicInt + (int) wrappedInt;  
        System.out.println("基本类型的新值: " + basicInt);  
          
        // 装箱和拆箱操作  
        Integer boxedInt = basicInt; // 装箱操作,将基本类型转换为包装类型  
        System.out.println("装箱后的值: " + boxedInt);  
          
        int unboxedInt = (int) boxedInt; // 拆箱操作,将包装类型转换为基本类型  
        System.out.println("拆箱后的值: " + unboxedInt);  
    }  
}

✅如何理解自动拆装箱?

✅拆箱与装箱

包装类是对基本类型的包装,所以,把基本数据类型转换成包装类的过程就是装箱,反之,把包装类转换成基本数据类型的过程就是拆箱

看一段代码:

// 装箱  
Integer boxedInt = 10; // 将基本类型int转换为包装类Integer  
  
// 拆箱  
int unboxedInt = boxedInt; // 将包装类Integer转换为基本类型int

在这个例子中,我们将一个基本类型int的值10赋值给一个包装类Integer的变量boxedInt。由于Java的类型转换机制,我们可以将基本类型的值直接赋值给包装类的变量,这就是装箱过程。

接下来,我们将一个包装类Integer的变量boxedInt赋值给一个基本类型int的变量unboxedInt。由于Java的类型转换机制,我们可以将包装类的值直接赋值给基本类型的变量,这就是拆箱过程。

需要注意的是,在进行装箱和拆箱操作时,Java会自动进行类型转换。但是,如果基本类型的值超出了包装类所能表示的范围,那么会发生溢出或下溢的情况。因此,在进行装箱和拆箱操作时,需要注意数据类型的范围和溢出问题。

✅自动拆装箱

在Java SE5中,为了减少开发人员的工作作,Java提供了自动拆箱与自动装箱功能。


自动装箱 : 就是将基本数据类型自动转换成对应的包装类。

自动拆箱: 就是将包装类自动转换成对应的基本数据类型。

看一段代码:

import java.util.Scanner;  
  
public class AdvancedCalculator {  
    public static void main(String[] args) {  
        Scanner scanner = new Scanner(System.in);  
          
        System.out.print("请输入第一个数字:");  
        Integer num1 = scanner.nextInt(); // 自动装箱  
          
        System.out.print("请输入第二个数字:");  
        Integer num2 = scanner.nextInt(); // 自动装箱  
          
        System.out.println("请选择运算:");  
        System.out.println("1. 加法");  
        System.out.println("2. 减法");  
        System.out.println("3. 乘法");  
        System.out.println("4. 除法");  
          
        int operation = scanner.nextInt(); // 自动装箱  
          
        switch (operation) {  
            case 1: // 加法  
                Integer result = add(num1, num2); // 自动拆箱,将Integer对象转换为int值进行加法运算  
                System.out.println("加法结果为:" + result); // 自动装箱,将int值转换为Integer对象输出  
                break;  
            case 2: // 减法  
                result = subtract(num1, num2); // 自动拆箱,将Integer对象转换为int值进行减法运算  
                System.out.println("减法结果为:" + result); // 自动装箱,将int值转换为Integer对象输出  
                break;  
            case 3: // 乘法  
                result = multiply(num1, num2); // 自动拆箱,将Integer对象转换为int值进行乘法运算  
                System.out.println("乘法结果为:" + result); // 自动装箱,将int值转换为Integer对象输出  
                break;  
            case 4: // 除法  
                result = divide(num1, num2); // 自动拆箱,将Integer对象转换为int值进行除法运算  
                System.out.println("除法结果为:" + result); // 自动装箱,将int值转换为Integer对象输出  
                break;  
            default:  
                System.out.println("无效的运算选择!");  
                break;  
        }  
    }  
      
    public static Integer add(Integer a, Integer b) {  
        return a + b; // 自动拆箱,将输入的两个Integer对象转换为int值进行加法运算  
    }  
      
    public static Integer subtract(Integer a, Integer b) {  
        return a - b; // 自动拆箱,将输入的两个Integer对象转换为int值进行减法运算  
    }  
      
    public static Integer multiply(Integer a, Integer b) {  
        return a * b; // 自动拆箱,将输入的两个Integer对象转换为int值进行乘法运算  
    }  
      
    public static Integer divide(Integer a, Integer b) {  
        if (b == 0) { // 检查除数是否为零,避免出现异常情况  
            System.out.println("除数不能为零!");  
            return null; // 返回null表示除法运算失败  
        } else {  
            return a / b; // 自动拆箱,将输入的两个Integer对象转换为int值进行除法运算,并返回结果  
        }  
    }  
}

在上面的示例中,使用Java的自动装箱和拆箱机制,将用户输入的int值转换为Integer对象,并在计算结果时将Integer对象转换为int值输出。在add、subtract、multiply和divide方法中,我们将输入的两个Integer对象转换为int值进行相应的运算,并返回结果。在divide方法中,我们还需要检查除数是否为零,以避免出现异常情况。这个过程就是自动拆箱的过程。



✅自动拆装箱原理

自动装箱都是通过包装类的 value0f() 方法来实现的自动拆箱都是通过包装类对象的 xxxValue()来实现的。


如: int的自动装箱都是通过 Integer.value0f() 方法来实现的,Integer的自动拆箱都是通过 nteger.intValue()来实现的。

✅哪些地方会自动拆装箱?


我们了解过原理之后,在来看一下,什么情况下,Java会帮我们进行自动拆装箱。前面提到的变量的初始化和赋值的场景就不个绍了,那是最简单的也最容易理解的。
我们主要来看一下,那些可能被忽略的场景。

🍁场景一:将基本数据类型放入集合类


我们知道,Java中的集合类只能接收对象类型,那么以下代码为什么会不报错呢?
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i ++){
	li.add(i);
}

将上面代码进行反编译,可以得到以下代码:

List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50, i ++){
	li.add(Integer.value0f(i));
}

以上,我们可以得出结论,当我们把基本数据类型放入集合类中的时候,会进行自动装箱。

🍁场景二:包装类型和基本类型的大小比较


有没有人想过,当我们对Integer对象与基本类型进行大小比较的时候,实际上比较的是什么内容呢? 看以下代码:
Integer a=1;
System.out.println(a==1?"等于":"不等于");
Boolean bool=false;
System.out.printIn(bool?"真":"假");

对以上代码进行反编译,得到以下代码:

Integer a=1;
System.out.println(a.intValue()==1?"等于":"不等于");
Boolean bool=false;
Svstem.out.println(bool.booleanValue?"真":"假");

可以看到,包装类与基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型,然后进行比较的。

🍁场景三:包装类型的运算


有没有人想过,当我们对Integer对象进行四则运算的时候,是如何进行的呢? 看以下代码:
Integer i = 10;
Integer j = 20;

System.out.println(i+j);

反编译以后:

Integer i= Integer.value0f(10);
Integer j = Integer.valueOf(20);
System.out.println(i.intValue() + j.intValue());

我们发现,两个包装类型之间的运算,会被自动拆箱成基本类型进行。

🍁场景四:三目运算符的使用


这是很多人不知道的一个场景,作者也是一次线上的血淋淋的Bug发生后才了解到的一种案例。看一个简单的三目运算符的代码:

boolean flag = true; //设置成true,保证条件表达式的表达式二一定可以执行
boolean simpleBoolean = false; //定义一个基本数据类型的boolean变量
Boolean nullBoolean = null;//定义一个包装类对象类型的Boolean变量,值为null


boolean x = flag ? nullBoolean : simpleBoolean; //使用三目运算符并给x变量赋值

很多人不知道,boolean x = flag ? nullBoolean : simpleBoolean ;这一行,会发生自动拆箱。反编译后代码如下:

boolean flag = true;
boolean simpleBoolean = false;
Boolean nu11Boolean = null;
boolean x = flag ? nullBoolean.booleanValue() : simpleBoolean;

这其实是三目运算符的语法规范。当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。
可以看到,反编译后的代码的最后一行,编译器帮我们做了一次自动拆箱,而就是因为这次自动拆箱,导致代码出现对于一个null对象 (nullBoolean.booleanValue0) 的调用,导致了NPE。

🍁场景五:函数参数与返回值


这个比较容易理解,这季节上代码哈。
//自动拆箱
public int getNum1(Integer num) {
	return num;
}

//自动装箱
public Integer getNum2(int num) {
	return num;
}

✅自动拆装箱与缓存


Java SE的自动拆装箱还提供了一个和缓存有关的功能,我们先来看以下代码,猜测一下输出结果:
public static void main(String... strings) {
	
	Integer integer1 = 3;
	Integer integer2 = 3;

	if (integer1 == integer2)//这里省略了大括号是可以的
		System.out.println("integer1 == integer2") ;
	else
		System.out.println("integer1 != integer2");

	Integer integer3 = 300;
	Integer integer4 = 300;

	if (integer3 == integer4)
		System.out.println("integer3 == integer4");
	else
		System.out.println("integer3 != integer4");
	
}

我们普遍认为上面的两人判新的结果都是talse。虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个i判断都是false的。在Java中,==比较的是对象用,而equals比较的是值。所以,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都将返回false。奇怪的是,这里两个类似的i条件判断返回不同的布尔值。

上面这段代码真正的输出结果:
在这里插入图片描述
原因就和Integer中的缓存机制有关。在Java 5中,在nteger的操作上引入了一个新功能来节省内存和提高性能。
整型对象通过使用相同的对象引用实现了缓存和重用。

适用于整数值区间 -128 至 +127





只适用于自动装箱,使用构造函数创建对象不适用。

我们只需要知道,当需要进行自动装箱时,如果数字在-128至127之间时,会直接使用缓存中的对象,而不是重新创建个对象。


其中的javadoc详细的说明了缓存支持-128到127之间的自动装箱过程。最大值127可以通过 -XX:AutoBoxCacheMax=size 修改。


实际上这个功能在Java 5中引入的时侯;范围是固定的-128至 +127。后来在Java 6中,可以通过 java.lang.Integer.IntegerCache.high 设置最大值。


这使我们可以根据应用程序的实际情况灵活地调整来提高性能。到底是什么原因选择这个-128到127范围呢?因为这个范围的数字是最被广泛使用的。在程序中,第一次使用Integer的时候也需要一定的额外时间来初始化这个缓
存。


在Boxing Conversion部分的Java语言规范(LS)规定如下:


如果一个变量p的值是:

-128127之间的整数(S3.19.1)

truefalse的布尔值 (s3.10.3)

'\u8808''\u897F'之间的字符(§3.19.4)

范围内的时,将p包装成a和b两个对象时,可以直接使用a==b判断a和b的值是否相等。

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

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

相关文章

C++20形式的utf-8字符串转宽字符串,不依赖编译器编码形式

默认的char[]编码都是要看编译器编译选项的&#xff0c;你选了ANSI那它就是ANSI&#xff0c;你选了UTF8那它就是UTF8. 【注意&#xff1a;经典DevC只支持ANSI编码&#xff08;痛苦&#xff09;&#xff1b;上图是小熊猫DevC&#xff0c;则有这个选项】 这一点对我的代码造成了…

【教3妹学编程-算法题】循环移位后的矩阵相似检查

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&…

Ubuntu 常用命令之 apt-get 命令用法介绍

apt-get是Ubuntu系统下的一个命令行工具&#xff0c;用于处理包。这个命令可以自动下载和安装软件包及其依赖项。它是Advanced Packaging Tool (APT)的一部分&#xff0c;APT是处理包的高级工具&#xff0c;可以处理复杂的包关系&#xff0c;如依赖关系等。 apt-get命令的常见…

linux: ip route 与 route 用法详解与对比

文章目录 1. 引言2. ip route2.1 描述2.2 语法2.3 参数2.4 例子 3. route3.1 描述3.2 语法3.3 参数3.4 例子 4. 对比5. 参考 1. 引言 本文主要介绍 ip route 以及 route 的用法和区别。 2. ip route 2.1 描述 用于管理静态路由表。linux 系统中&#xff0c;可以自定义从 1&…

聚类算法及可视化方法的实践与探索

簇内平方和表示数据点到其簇内质心的距离的平方和&#xff0c;公式如下&#xff1a; 其中&#xff0c; 是k簇数&#xff0c; ni是第 i 个簇的样本数&#xff0c; xij是第 i个簇中的第 j 个样本。 import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sk…

Python Opencv实践 - 手势音量控制

本文基于前面的手部跟踪功能做一个手势音量控制功能&#xff0c;代码用到了前面手部跟踪封装的HandDetector.这篇文章在这里&#xff1a; Python Opencv实践 - 手部跟踪-CSDN博客文章浏览阅读626次&#xff0c;点赞11次&#xff0c;收藏7次。使用mediapipe库做手部的实时跟踪&…

47 星南二楼

动态规划&#xff0c;相当于求解最长子序列问题 #include <iostream> using namespace::std; using std::cout; using std::cin; int n; int a[5100],dp[5100];int xnel(int n, int a[]) {int result 0;for(int i0; i<n; i){for(int j0; j<i; j){if(a[j]<a[…

node版本与npm版本不对应的解决方案

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 错误情况 今天遇到了个问题&#xff0c;原来用的node的版本是v14.16.0的&#xff0c;后来升级到了最新版20多的时候&#xff0c;以前的项目启动不了。 于是我手动将node卸载了&#xff0c…

【2023年网络安全优秀创新成果大赛专刊】银行数据安全解决方案(天空卫士)

在2023年网络安全优秀创新成果大赛&#xff0c;成都分站中&#xff0c;天空卫士银行数据安全方案获得优秀解决方案奖。与此同时&#xff0c;天空卫士受信息安全杂志邀请&#xff0c;编写《银行数据安全解决方案》。12月6日&#xff0c;天空卫士编写的《银行数据安全解决方案》做…

DAY11

问题一&#xff1a;指针与引用的区别 疑问 为什么引用的本质是指针常量&#xff0c;但是对它求sizeof却是变量所占内存空间的大小那&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 1.引用是给变…

Playground AI刚刚推出了它的新宠儿——Playground V2,去试试?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

令人惊叹的代码技巧

在编程世界中&#xff0c;有一些令人惊叹的代码技巧和巧妙的实现方式。以下是一些我见过的令人印象深刻的代码技巧&#xff1a; 函数式编程魔法&#xff1a; 使用函数式编程的一些特性&#xff0c;比如高阶函数、匿名函数和Lambda表达式&#xff0c;可以使代码更为简洁、易读。…

(9)Linux Git的介绍以及缓冲区

&#x1f4ad; 前言 本章我们先对缓冲区的概念进行一个详细的探究&#xff0c;之后会带着大家一步步去编写一个简陋的 "进度条" 小程序。最后我们来介绍一下 Git&#xff0c;着重讲解一下 Git 三板斧&#xff0c;一般只要掌握三板斧就基本够用了。 缓冲区&#xff…

Redis权限管理体系(三): ACL 配置持久化

点击上方蓝字关注我 前面我们已经了解了ACL用户管理的用途及使用&#xff1a; Redis权限管理体系(一&#xff09;&#xff1a;客户端名及用户名 Redis权限管理体系(二&#xff09;&#xff1a;终于等来了Redis权限控制体系ACL 但因默认配置中ACL的配置未持久化&#xff0c;因此…

oracle怎样才算开启了内存大页?

oracle怎样才算开启了内存大页&#xff1f; 关键核查下面三点&#xff1a; 1./etc/sysctl.conf vm.nr_hugepages16384这是给了32G&#xff0c;计划sga给30G&#xff0c;一般需多分配2-4G sysctl -p生效 看cat /proc/meminfo|grep Huge啥结果&#xff1f; 这种明显是配了…

Go项目快速集成Swagger UI

swag Swag将Go的注释转换为Swagger2.0文档。我们为流行的 Go Web Framework 创建了各种插件&#xff0c;这样可以与现有Go项目快速集成&#xff08;使用Swagger UI&#xff09;。 目录 快速开始支持的Web框架如何与Gin集成格式化说明开发现状声明式注释格式 通用API信息API操…

【每日一题】【12.20】2828.判别首字母缩略词

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 1.题目链接 2828. 判别首字母缩略词https://leetcode.cn/problems/check-if-a-string-is-an-acronym-of-words/ 2.题目描述 今天…

RTDETR论文快速理解和代码快速实现(训练与预测)

文章目录 前言一、摘要二、论文目的三、论文贡献四、模型结构1、模型整体结构2、backbone结构3、neck结构4、混合编码器(neck) 五、RTDERT模型训练(data-->train)1、环境安装2、训练1、数据准备2、数据yaml文件3、训练代码4、训练运行结果 3、推理1、推理代码2、推理运行结果…

Nginx快速入门:安装目录结构详解及核心配置解读(二)

0. 引言 上节我们讲解了nginx的应用场景和安装&#xff0c;本节继续针对nginx的各个目录文件进行讲解&#xff0c;让大家更加深入的认识nginx。并通过一个实操案例&#xff0c;带大家来实际认知nginx的核心配置 1. nginx安装目录结构 首先nginx的默认安装目录为&#xff1a;…

原子学习笔记3——使用tslib库

一、tslib介绍 tslib 是专门为触摸屏设备所开发的 Linux 应用层函数库&#xff0c;并且是开源。 tslib 为触摸屏驱动和应用层之间的适配层&#xff0c;它把应用程序中读取触摸屏 struct input_event 类型数据&#xff08;这是输入设备上报给应用层的原始数据&#xff09;并进行…