什么是自动装箱和拆箱?很简单,下面两行代码就可以看到装箱和拆箱的过程//automaticboxingIntegertotal=99;//automaticunboxinginttotalprim=total;简单来说,装箱就是将基本数据类型自动转换为包装类型;拆箱是将包装器类型自动转换为原始数据类型。下面看一下需要装箱和拆箱的类型:这个过程是自动执行的,所以我们要看一下它的执行过程:反编译class文件后得到如下内容:1javap-cStringTestIntegertotal=99;上面代码执行时,系统为我们执行:Integertotal=Integer.valueOf(99);inttotalprim=total;当上面的代码执行时,系统会为我们执行:inttotalprim=total.intValue();下面以Integer为例来分析一下它的源码:1.我们看一下Integer.valueOf函数publicclassMain{publicstaticvoidmain(String[]args){//自动装箱Integertotal=99;//自定义拆箱inttotalprim=total;}}首先会判断i的大小:如果i小于-128或者大于等于128,则创建一个Integer对象,否则执行SMALL_VALUES[i+128]。首先我们看一下Integer的构造函数:privatefinalintvalue;publicInteger(intvalue){this.value=value;}publicInteger(Stringstring)throwsNumberFormatException{this(parseInt(string));}它定义了创建一个value变量,创建一个Integer对象,并初始化该变量。第二个输入是String变量,会先转换成int值,再初始化。我们来看看SMALL_VALUES[i+128]是什么:1privatestaticfinalInteger[]SMALL_VALUES=newInteger[256];它是一个静态的Integer数组对象,也就是说最终的valueOf返回的是一个Integer对象。所以我们这里可以总结一下:装箱的过程会创建相应的对象,会消耗内存,所以装箱的过程会增加内存消耗,影响性能。2.然后看intValue函数@OverridepublicintintValue(){returnvalue;}这个很简单,直接返回值即可。相关问题上面我们看到,在Integer的构造函数中,有两种情况:1.i>=128||i<-128=====>newInteger(i)2.i<128&&i>=-128=====>SMALL_VALUES[i+128]privatestaticfinalInteger[]SMALL_VALUES=newInteger[256];SMALL_VALUES已经创建好了,也就是说当i>=128||i<-128将创建不同的对象。当i<128&&i>=-128时,根据i的值返回已经创建的指定对象。说这些可能不是很清楚,举个例子:publicclassMain{publicstaticvoidmain(String[]args){Integeri1=100;整数i2=100;整数i3=200;整数i4=200;System.out.println(i1==i2);//真System.out.println(i3==i4);//false}}后面的代码,我们可以看出他们的执行结果是不一样的,为什么,看我们上面的描述。1、i1和i2会自动装箱并执行valueOf函数。它们的值在(-128,128)范围内,它们会在SMALL_VALUES数组中得到相同的对象SMALL_VALUES[228],并且它们指的是相同的Integer对象,所以它们必须相等。2、i3和i4也会自动装箱,会执行valueOf函数,他们的值大于128,所以会执行newInteger(200),也就是说他们会创建两个不同的对象,所以一定不相等。我们来看另一个例子:publicclassMain{publicstaticvoidmain(String[]args){Doublei1=100.0;Doublei2=100.0;Doublei3=200.0;Doublei4=200.0;System.out.println(i1==i2);//falseSystem.out.println(i3==i4);//false}}看上面的执行结果,和Integer不一样,所以也不要惊讶,因为他们的valueOf实现是不一样的,而且结果肯定是不同的,为什么不统一呢?这个很好理解,因为对于Integer来说,(-128,128]之间只有256个固定值,所以为了避免多次创建对象,我们有预先创建了一个大小为256的Integer数组SMALL_VALUES,所以如果值在这个范围内,我们可以直接返回我们预先创建的对象。但是对于Double类型,我们就是不能这样做,因为它在这个范围内的个数是无限的。综上所述,一定范围内的整数值的个数是有限制的,而浮点数则没有。所以Double中的做法很直接,就是直接创建一个对象,所以每次创建的对象都不一样。publicstaticDoublevalueOf(doubled){returnnewDouble(d);}我们来做个分类:Integer派:Integer,Short,Byte,Character,Long这些类的valueOf方法的实现都是类似的。Double派:Double和Float的valueOf方法实现类似。每次返回不同的对象。我们对Integer派系做一个总结,如下图所示:再来看另一种情况:publicclassMain{publicstaticvoidmain(String[]args){Booleani1=false;布尔值i2=false;布尔i3=真;布尔i4=真;System.out.println(i1==i2);//trueSystem.out.println(i3==i4);//true}}可以看到返回的都是true,也就是他们都返回同一个对象的时候执行值。publicstaticBooleanvalueOf(booleanb){返回b?Boolean.TRUE:Boolean.FALSE;}可以看到它并没有创建对象,因为内部已经提前创建了两个对象,因为它只有两种情况,所以是为了避免重复创建太多对象。publicstaticfinalBooleanTRUE=newBoolean(true);publicstaticfinalBooleanFALSE=newBoolean(false);上面已经介绍了几种情况,其他情况将在下面进一步讨论。整数num1=400;intnum2=400;System.out.println(num1==num2);//true//表示num1==num2已经拆箱Integernum1=100;intnum2=100;System.out.println(num1.equals(num2));//true我们看一下equals的源码:@Overridepublicbooleanequals(Objecto){return(oinstanceofInteger)&&(((Integer)o).value==value);}我们指定equal比较内容本身,我们也可以看到equal的参数是一个Object对象,而我们传入的是一个int类型,所以会先装箱,然后比较,之所以返回true,是因为它比较对象中的值。整数num1=100;整数num2=100;长整数num3=200l;System.out.println(num1+num2);//200System.out.println(num3==(num1+num2));//trueSystem.out。println(num3.equals(num1+num2));//false1,当基本数据类型与封装类进行==、+、-、*、/操作时,封装类将被拆箱,由基本数据类型进行计算。2.num3.equals(num1+num2)为假的原因很简单。下面按照代码实现来解释一下:@Overridepublicbooleanequals(Objecto){return(oinstanceofLong)&&(((Long)o).value==value);}必须满足两个条件才为真:1,类型相同2,内容相同上面返回false的原因是类型不同。Integernum1=100;Ingegernum2=200;Longnum3=300l;System.out.println(num3==(num1+num2));//true我们来反编译一些这个class文件:javap-cStringTest可以看到在计算的时候,先unboxnum3(执行num3的longValue得到基本类型long的值300),然后unboxnum1和mum2(执行intValue的num1和num2分别得到值100和200),然后进行相关的基本操作。让我们对基本类型做一个测试:intnum1=100;intnum2=200;长妈妈3=300;System.out.println(num3==(num1+num2));//true解释了为什么top会返回true。所以,当==运算符的两个操作数是包装类型的引用时,比较它们是否指向同一个对象,如果其中一个操作数是表达式(即包含算术运算),则值为比较(即会触发自动拆箱的过程)。陷阱一:整数integer100=null;intint100=整数100;这两行代码是完全合法的,可以通过编译,但是在运行时,会抛出空指针异常。其中,integer100是一个Integer类型的对象,当然可以指向null。但是在第二行,integer100会被拆箱,也就是intValue()方法会在一个空对象上执行,当然会抛出空指针异常。所以在有拆箱操作的时候要特别注意封装类对象是否为null。总结1.你需要知道什么时候装箱和拆箱。2.装箱操作会创建对象。频繁的装箱操作会消耗大量内存,影响性能,所以应该尽量避免装箱。3.equals(Objecto)因为原来equals方法中的参数类型是封装类型,所以传入的参数类型(a)是原来的数据类型,所以会自动装箱,否则会拆箱4.当用==比较两种不同的类型时,包装类需要拆箱。同类型用==比较时,会自动拆箱或装箱。来源:https://www.cnblogs.com/wang-...近期热点文章推荐:1.1000+Java面试题及答案(2021最新版)2.别再满脑子if/else了,试试策略模式,太好吃了!!3.操!Java中xx≠null的新语法是什么?4、SpringBoot2.6正式发布,一大波新特性。.5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!
