(自动)装箱and(自动)拆箱

news/2025/1/20 8:11:27/

目录

【1】前言

【2】实现原理

【3】自动装箱和拆箱的时机

【4】自动装拆箱带来的问题


【1】前言

     在说到拆箱和装箱之前,需要了解Java中有八种基本的数据类型,分别是:byte、short、char、int、long、float、double和boolean。这八种基本类型在Java中都有对应的包装类型:Byte、Short、Character、Integer、Long、Float、Double以及Boolean 。

      有了基本类型为什么还需要包装类型呢?这是由Java本身的语言特性决定的,Java是一种面向对象的编程语言,在学习Java之初就被明确灌输了一个概念:OOP,即面向对象编程。一切皆对象。但是基本类型是不具备Java中对象的某些特征,对象内部可以封装一系列属性和行为,但是这些在基本数据类型中都无法满足,所以对应的包装类型就应运而生了。

       这里的装箱和拆箱的概念描述的其实就是Java中这八种基本数据类型和对应的包装类型之间的转换过程。我们把基本数据类型转换成对应的包装类型的过程叫做装箱。反之就是拆箱。在Java中的装箱和拆箱不是人为操作的,是程序在编译的时候编译器帮助我们完成这项任务的,因此说它是自动的。

【2】为什么需要自动拆/装箱呢?

1)方便

       首先就是方便程序员的编码,我们在编码过程中,可以不需要考虑包装类和基本类型之间的转换操作,这一步由编译器自动替我们完成,开发人员可以有更多的精力集中与具体的业务逻辑。否则的话,一个简单的数字赋值给包装类就得写两句代码,即:首先生成包装类型对象,然后将对象转换成基本数据类型。而这种操作是代码中使用频率很高的操作,导致代码书写量增多。

2)节约空间

       我们在查阅对应包装类的源代码时可以看到,大部分包装类型的valueOf方法都会有缓存的操作,即:将某段范围内的数据缓存起来,创建时如果在这段范围内,直接返回已经缓存的这些对象,这样保证在一定范围内的数据可以直接复用,而不必要重新生成

       这么设计的目的因为:小数字的使用频率很高,将小数字缓存起来,让其仅有一个对象,可以起到节约存储空间的作用。这里其实采用的是一种叫做享元模式的设计模式。可以去具体了解以下这种设计模式,这里就不再过多赘述。

【2】实现原理

1)装箱

        可以看到对于数值类型直接赋值给包装类型,有一个自动装箱的操作,而自动装箱的操作就是利用了Integer中的valueOf方法,这就是前面在节约空间那部分提到的valueOf方法。Integer的valueOf方法中具有缓存的功能,也就是说在数值为-128到127之间的数据,都是被构造成同一个对象,这就是上面提到的享元模式的设计思路:

      注意:尽量不要使用【3】这种方式创建对象,这个构造方法被标记为Deprecated,也就是过时了 。利用构造器构造出来的对象不会经过取缓存操作,所以对于new Integer(1)的操作,得到的Integer对象与e或f进行==比较时,得到的会是false。它的注释中建议使用【4】valueOf进行构建对象。

      其实其他七种包装类型的valueOf方法大多都是这个享元设计模式的逻辑,但是有两个除外:Float和Double。这个其实也很好理解:因为Integer这种类型的数据,-128到127之间的数据是有限个,总共就256个数字,但是对于Float和Double这种类型,它们之间的数据个数就无法计算了,所以它两个就没有采用这种缓存的方式。下面是其他包装类型中的valueOf方法的源码:

 

       通过上面的代码截图可以看到,对于Float和Double都是直接使用了构造器直接构造对应包装类型的对象。对于Boolean类型,就是固定的两个TRUE和FALSE两个常量,它们不会出现变化,这也属于一种缓存。

      对于Byte类型,它是直接全部缓存了,这里使用了cache数组,它在Byte类中定义和初始化如下:

        所以cache数组中存储的就是-128到127范围的所有数。在构建时直接定位到具体的数组位置中去,并将该位置上的数值直接返回即可。

       其余数据类型基本逻辑都差不多了,都有一个缓存值范围,如果超过了,就利用构造器直接构造,否则直接返回缓存的对象。

2)拆箱

上面介绍的valueOf方法是装箱操作的时候使用的,还有一个拆箱操作,看下面这个例子:

上面代码反编译之后就得到:

        可以看到第一步进行了自动装箱操作,在第三行中,基本数据类型和包装类型进行运算,需要将包装类型进行拆箱操作,用到了intValue方法。这个方法其实在源码中很简单,就是一句话,返回value。我们知道任何包装类型,内部都有一个基本数据类型的字段用于存储对应基本类型的值,这个字段就是value。

       相应的其他包装类型在进行拆箱的时候,都会调用对应的xxxValue方法,例如:byteValue、shortValue等等方法。其实内部逻辑都是一样,直接返回存储的value值。

【3】自动装箱和拆箱的时机

1)直接赋值 

       这个情况其实在前面介绍自动装箱的操作的时候,举例代码中就是这种情况,将一个字面量直接赋值给对应包装类型会触发自动装箱操作。 

2)函数参数

       

3)集合操作

       在Java的集合中,泛型只能是包装类型,但是我们在存储数据的时候,一般都是直接存储对应的基本类型数据,这里就有一个自动装箱的过程。

4)运算符运算

       上面在拆箱操作的时候利用的就是这个特性,当基本数据类型和对应的包装类型进行算术运算时,包装类型会首先进行自动拆箱,然后再与基本数据类型的数据进行运算。

       说到运算符,这里对于自动拆箱有一个需要注意的地方:

       这种情况编译是可以通过的,但是在运行的时候会抛出空指针异常,这就是自动拆箱导致的这种错误。因为自动拆箱会调用intValue方法,但是此时a是null,所以会抛异常。平时在使用的时候,注意非空判断即可。

【4】自动装拆箱带来的问题

 1)==比较

        首先就是前面提到的关于==操作符的结果问题,因为自动装箱的机制,我们不能依赖于==操作符,它在一定范围内数值相同为true,但是在更多的空间中,数值相同的包装类型对象比较的结果为false。如果需要比较,可以考虑使用equals比较或者将其转换成对应的基本类型再进行比较可以保证结果的一致性。

2)空指针异常

        这是上面在说到运算符的时候提到的一种情况,因为有自动拆箱的机制,如果初始的包装类型对象为null,那么在自动拆箱的时候的就会报NullPointerException,在使用时需要格外注意,在使用之前进行非空判定,保证程序的正常运行。

3)内存浪费

这里有个例子:

面代码中的 sum+=i 这个操作其实就是拆箱再装箱的过程,拆箱过程是发生在相加的时候,sum本身是Integer,自动拆箱成int与 i 相加。将得到的结果赋值给sum的时候,又会进行自动装箱,所以上面的for循环体中一句话,在编译后会变为:

       每次调用valueOf方法都会返回一个Integer对象,所以在进行了5000次循环后,会出现大量的无用对象造成内容空间的浪费,同时加重了垃圾回收的工作量,所以在日常编码过程中需要格外注意,避免出现这种浪费现象。

4)方法重载问题

       每次调用valueOf方法都会返回一个Integer对象,所以在进行了5000次循环后,会出现大量的无用对象造成内容空间的浪费,同时加重了垃圾回收的工作量,所以在日常编码过程中需要格外注意,避免出现这种浪费现象。

      所以可以发现,当出现这种情况的时候,是不会发生自动装箱和拆箱操作的。可以正常区分。

有人身居高堂久睡不醒,有人身居陋巷仍以萤火为光。

前路昭然,你我仍需奋进!

铁铁们加油!!!


http://www.ppmy.cn/news/534194.html

相关文章

关于元胞自动机

元胞自动机(cellular automata,CA) 是一种时间、空间、状态都离散,空间相互作用和时间因果关系为局部的网格动力学模型,具有模拟复杂系统时空演化过程的能力。 其实在去年暑假准备国赛的时候试图过自学,但受限于,网上…

自动拆箱与自动装箱

为什么需要包装类 Java 中为了提高效率,提供了八种基本数据类型,为什么还要提供包装类呢? 这个问题,其实前面已经有了答案,因为 Java 是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如…

练腹肌

1:练腹肌最好的办法还是仰卧起坐,每次做100-200个,20-30个为1组,最少要做5组,具体的要看个人情况。可以适当增加点重量,手拿个哑铃或铁饼什么的,放在脑后,效果更好。 2:…

韩金氏秀腹宝

韩金氏秀腹宝:www.hxdj.net秀腹宝首要成分: 韩国金氏集团和韩国首尔大学女子生殖医学研讨中间在关于产后妊娠纹疑问通过多次配方调整实验,结尾判定以PAL-GQPR胶原蛋白、橄榄油、芸香苷、水溶性辣椒精华、雪莲、薰衣草、VE、VB6、VC等组方又配…

自动装箱和自动拆箱

在java中一共有8种基本类型,并且在jdk1.4的时候添加了对应的八个包装类型如下表所示: 基本类型与包装类型对照表 intIntegershortShortlongLongdoubleDoublefloatFloatcharCharacterbyteBytebooleanBoolean 都知道,java中的类型可以分为两类…

什么是元胞自动机

看了网上的资料和大神Stephen Wolfram的论文,对元胞自动机有了一点基本的了解。 先贴一段维基百科的解释: 细胞自动机(英语:Cellular automaton),又称格状自动机、元胞自动机,是一种离散模型&a…

咕咕机vs喵喵机测评

咕咕机vs喵喵机测评 本次对比测评的机子,来自之前妹妹入手的喵喵机和我刚刚入手的咕咕机。 之前妹妹有买过喵喵机,觉得很方便想推荐给我,碰巧咕咕机推出了新款,价格合算,外表美观,于是干脆入手了咕咕机。顺…

元胞自动机概念与实例

简介:元胞自动机(cellular automata,CA) 是一种时间、空间、状态都离散,空间相互作用和时间因果关系为局部的网格动力学模型,具有模拟复杂系统时空演化过程的能力。 主要内容: 一、元胞 元胞可以是数字,字…