首页编程java编程java什么是装箱 java 什么是拆箱和装箱,拆箱和装箱 嘛用啊

java什么是装箱 java 什么是拆箱和装箱,拆箱和装箱 嘛用啊

编程之家2023-10-1293次浏览

大家好,今天来为大家解答java什么是装箱这个问题的一些问题点,包括java 什么是拆箱和装箱,拆箱和装箱 嘛用啊也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~

java什么是装箱 java 什么是拆箱和装箱,拆箱和装箱 嘛用啊

java 为什么要有装箱和拆箱

把一个基本类型包装成一个类,一个是可以使这个类型具有很多可以调用的方法。二个是Java向面像对象语言的靠近。其实Java还不算是很纯的面向对象的语言。真正的面向对象,是没有基本数据类型的。它只有一种类型,就是对象。三个是在泛型中,基本类型是不可以做泛型参数的。如:List<int> list= new ArrayList<int>();这是不合法的。你只能这个样写List<Integer> list= new ArrayList<Integer>();也就是要用int型的包装类类型来解决基本类型不可以做泛型参数的问题。

一名话,包装类有更多的方法和用途,而这是基本类型没有的!!!

java什么时候触发装箱和拆箱

最近面试也遇到了这个问题,思考总结了一下。

java什么是装箱 java 什么是拆箱和装箱,拆箱和装箱 嘛用啊

装箱:在基本类型的值赋值给包装类型时触发。例如:Integer a= 1;

这时二进制文件中实际上是Integer a= Integer.valueOf(1);

拆箱:

java什么是装箱 java 什么是拆箱和装箱,拆箱和装箱 嘛用啊

1.在包装类型赋值给基本类型时触发。

例如:Integer a= 1;// a是Integer类型

int b= a;//将Integer类型赋值给int类型,触发拆箱

2.在做运算符运算时触发。

例如:

Integer a= 1;

Integer b= 2;

System.out.print(a* b);//这时a*b在二进制文件中被编译成a.intValue()* b.intValue();

注意点:

==运算时,如果 a和 b都是Integer类型,则不会拆箱,因为==也可以直接比较对象,表示a和b是否指向同一对象地址。因此这里并不是比较值是否相等了。而如果a和 b中有一个是int类型,另一个是Integer类型,则会触发拆箱,然后对两个int值进行比较。

Integer a= 128;

Integer b= 128;

Integer c= 127;

Integer d= 127;

System.out.print(a== b);//返回false

System.out.print(c== d);//返回true

原因是Integer的装箱(Integer.valueOf())方法会自动缓存-128~127之间的值,多次装箱同一个值实际上用的是同一个对象,因此这里 a== b是false,因为不是同一个对象,而 c==d是true,因为使用缓存中的同一个对象,而不是因为值相等。

Integer a= 127;

Integer e= new Integer(127);

Integer f= Integer.intValue(127);

System.out.println(a== e);//返回false,不是同一个对象

System.out.println(a== f);//返回true,是缓存中同一个对象

欢迎修改补充...

java 什么是拆箱和装箱,拆箱和装箱 嘛用啊

详解Java的自动装箱与拆箱(Autoboxing and unboxing)

一、什么是自动装箱拆箱

很简单,下面两句代码就可以看到装箱和拆箱过程

//自动装箱

Integertotal=99;

//自定拆箱

inttotalprim=total;

简单一点说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。

下面我们来看看需要装箱拆箱的类型有哪些:

这个过程是自动执行的,那么我们需要看看它的执行过程:

publicclassMain{

publicstaticvoidmain(String[]args){

//自动装箱

Integertotal=99;

//自定拆箱

inttotalprim=total;

}

}

反编译class文件之后得到如下内容:

javap-cStringTest

Integer total= 99;

执行上面那句代码的时候,系统为我们执行了:

Integer total= Integer.valueOf(99);

int totalprim= total;

执行上面那句代码的时候,系统为我们执行了:

int totalprim= total.intValue();

我们现在就以Integer为例,来分析一下它的源码:

1、首先来看看Integer.valueOf函数

publicstaticIntegervalueOf(inti){

returni>=128||i<-128?newInteger(i):SMALL_VALUES[i+128];

}

它会首先判断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]是什么东西:

privatestaticfinalInteger[]SMALL_VALUES=newInteger[256];

它是一个静态的Integer数组对象,也就是说最终valueOf返回的都是一个Integer对象。

所以我们这里可以总结一点:装箱的过程会创建对应的对象,这个会消耗内存,所以装箱的过程会增加内存的消耗,影响性能。

2、接着看看intValue函数

@Override

publicintintValue(){

returnvalue;

}

这个很简单,直接返回value值即可。

二、相关问题

上面我们看到在Integer的构造函数中,它分两种情况:

1、i>= 128|| i<-128=====> new Integer(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;

Integeri2=100;

Integeri3=200;

Integeri4=200;

System.out.println(i1==i2);//true

System.out.println(i3==i4);//false

}

}

代码的后面,我们可以看到它们的执行结果是不一样的,为什么,在看看我们上面的说明。

1、i1和i2会进行自动装箱,执行了valueOf函数,它们的值在(-128,128]这个范围内,它们会拿到SMALL_VALUES数组里面的同一个对象SMALL_VALUES[228],它们引用到了同一个Integer对象,所以它们肯定是相等的。

2、i3和i4也会进行自动装箱,执行了valueOf函数,它们的值大于128,所以会执行new Integer(200),也就是说它们会分别创建两个不同的对象,所以它们肯定不等。

下面我们来看看另外一个例子:

publicclassMain{publicstaticvoidmain(String[]args){

Doublei1=100.0;

Doublei2=100.0;

Doublei3=200.0;

Doublei4=200.0;

System.out.println(i1==i2);//false

System.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;

Booleani2=false;

Booleani3=true;

Booleani4=true;

System.out.println(i1==i2);//true

System.out.println(i3==i4);//true

}

}

可以看到返回的都是true,也就是它们执行valueOf返回的都是相同的对象。

publicstaticBooleanvalueOf(booleanb){

returnb?Boolean.TRUE:Boolean.FALSE;

}

可以看到它并没有创建对象,因为在内部已经提前创建好两个对象,因为它只有两种情况,这样也是为了避免重复创建太多的对象。

publicstaticfinalBooleanTRUE=newBoolean(true);

publicstaticfinalBooleanFALSE=newBoolean(false);

上面把几种情况都介绍到了,下面来进一步讨论其他情况。

Integernum1=400;

intnum2=400;

System.out.println(num1==num2);//true

说明num1== num2进行了拆箱操作

Integernum1=100;

intnum2=100;

System.out.println(num1.equals(num2));//true

我们先来看看equals源码:

@Override

publicbooleanequals(Objecto){

return(oinstanceofInteger)&&(((Integer)o).value==value);

}

我们指定equal比较的是内容本身,并且我们也可以看到equal的参数是一个Object对象,我们传入的是一个int类型,所以首先会进行装箱,然后比较,之所以返回true,是由于它比较的是对象里面的value值。

Integernum1=100;

intnum2=100;

Longnum3=200l;

System.out.println(num1+num2);//200

System.out.println(num3==(num1+num2));//true

System.out.println(num3.equals(num1+num2));//false

1、当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。

2、对于num3.equals(num1+ num2)为false的原因很简单,我们还是根据代码实现来说明:

@Override

publicbooleanequals(Objecto){

return(oinstanceofLong)&&(((Long)o).value==value);

}

它必须满足两个条件才为true:

1、类型相同

2、内容相同

上面返回false的原因就是类型不同。

Integernum1=100;

Ingegernum2=200;

Longnum3=300l;

System.out.println(num3==(num1+num2));//true

我们来反编译一些这个class文件:javap-c StringTest

可以看到运算的时候首先对num3进行拆箱(执行num3的longValue得到基础类型为long的值300),然后对num1和mum2进行拆箱(分别执行了num1和num2的intValue得到基础类型为int的值100和200),然后进行相关的基础运算。

我们来对基础类型进行一个测试:

intnum1=100;

intnum2=200;

longmum3=300;

System.out.println(num3==(num1+num2));//true

上面就说明了为什么最上面会返回true.

所以,当“==”运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。

通过上面的分析我们需要知道两点:

1、什么时候会引发装箱和拆箱

2、装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免。

我有一个微信公众号,经常会分享一些Java技术相关的干货文章,还有一些学习资源。

如果你需要的话,可以用微信搜索“Java团长”或者“javatuanzhang”关注。

好了,文章到此结束,希望可以帮助到大家。

java 爬网站的叫j什么名字,Java测试工具Jtest是开源的么和Junit有什么区别java中=什么意思 java中这个符号“丨=”是什么意思