java可以用 lt =判断int吗_int 和 integer:装箱和拆箱的过程,会用到什么方法
本文转载自【微信公众号:五角钱的程序员,ID:xianglin965】,经微信公众号授权转载,如需转载与原文作者联系
原文标题《int 和 integer :装箱和拆箱的过程,会用到什么方法,你觉得这个会对性能有影响吗,原因是什么(百度一面)》
图丨pixabay
今天继续来讲面试,已经出了很多java一面真题系列文章了,之后也会整理成一个系列,欢迎持续关注哦。
话说干了这么多年的开发,只知道会用,怎么用,用什么,隐约也知道了为什么用,
但为啥JAVA总像一个犹抱琵琶半遮面的女子,总让人看不透,看不腻?应该就是基础不扎实了。
所以面试的时候却经常会被问到,我们根据面经来进行补短板,查漏补缺。下面开始今天的干货内容吧,
走起,记得点赞,点击在看哦。
自动装箱和拆箱从Java 1.5开始引入,目的是将原始类型值转自动地转换成对应的对象。自动装箱与拆箱的机制可以让我们在Java的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接。
如果你在Java1.5下进行过编程的话,你一定不会陌生这一点,你不能直接地向集合(Collections)中放入原始类型值,因为集合只接收对象。通常这种情况下你的做法是,将这些原始类型的值转换成对象,然后将这些转换的对象放入集合中。使用Integer,Double,Boolean等这些类我们可以将原始类型值转换成对应的对象,但是从某些程度可能使得代码不是那么简洁精炼。为了让代码简练,Java 1.5引入了具有在原始类型和对象类型自动转换的装箱和拆箱机制。但是自动装箱和拆箱并非完美,在使用时需要有一些注意事项,如果没有搞明白自动装箱和拆箱,可能会引起难以察觉的bug。
1、包装类型
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
包装类均位于java.lang包,包装类和基本数据类型的对应关系如下表所示
在这八个类名中,除了Integer和Character类以后,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写即可。
2、为什么需要包装类
很多人会有疑问,既然Java中为了提高效率,提供了八种基本数据类型,为什么还要提供包装类呢?
这个问题,其实前面已经有了答案,因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的。因为集合的容器要求元素是Object类型。
为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。
3、拆箱与装箱
在Java SE5之前,要进行装箱,可以通过以下代码:
Integer i = new Integer(10);
4、自动拆箱与自动装箱
自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。
在Java SE5中,为了减少开发人员的工作,Java提供了自动拆箱与自动装箱功能。
自动装箱: 就是将基本数据类型自动转换成对应的包装类。
自动拆箱:就是将包装类自动转换成对应的基本数据类型。
Integer i =10; //自动装箱int b= i; //自动拆箱
Integer i=10
可以替代
Integer i = new Integer(10);
,这就是因为Java帮我们提供了自动装箱的功能,不需要开发者手动去new一个Integer对象。
5、自动装箱与自动拆箱的实现原理
既然Java提供了自动拆装箱的能力,那么,我们就来看一下,到底是什么原理,Java是如何实现的自动拆装箱功能。
我们有以下自动拆装箱的代码:
public static void main(String[]args){Integer integer=1; //装箱 int i=integer; //拆箱}
对以上代码进行反编译后可以得到以下代码:
public static void main(String[]args){Integer integer=Integer.valueOf(1); int i=integer.intValue(); }
从上面反编译后的代码可以看出,int的自动装箱都是通过
Integer.valueOf()
方法来实现的,Integer的自动拆箱都是通过
integer.intValue
来实现的。如果读者感兴趣,可以试着将八种类型都反编译一遍 ,你会发现以下规律:
自动装箱都是通过包装类的
valueOf()
方法来实现的.自动拆箱都是通过包装类对象的
xxxValue()
来实现的。
6、哪些地方会自动拆装箱
我们了解过原理之后,在来看一下,什么情况下,Java会帮我们进行自动拆装箱。前面提到的变量的初始化和赋值的场景就不介绍了,那是最简单的也最容易理解的。
我们主要来看一下,那些可能被忽略的场景。
场景一、将基本数据类型放入集合类
我们知道,Java中的集合类只能接收对象类型,那么以下代码为什么会不报错呢?
List li = new ArrayList<>();for (int i = 1; i < 50; i ++){li.add(i);}
将上面代码进行反编译,可以得到以下代码:
List li = new ArrayList<>();for (int i = 1; i < 50; i += 2){li.add(Integer.valueOf(i));}
以上,我们可以得出结论,当我们把基本数据类型放入集合类中的时候,会进行自动装箱。
场景二、包装类型和基本类型的大小比较
有没有人想过,当我们对Integer对象与基本类型进行大小比较的时候,实际上比较的是什么内容呢?看以下代码:
Integer a=1;System.out.println(a==1?"等于":"不等于");Boolean bool=false;System.out.println(bool?"真":"假");
对以上代码进行反编译,得到以下代码:
Integer a=1;System.out.println(a.intValue()==1?"等于":"不等于");Boolean bool=false;System.out.println(bool.booleanValue?"真":"假");
可以看到,包装类与基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型,然后进行比较的。
场景三、包装类型的运算
有没有人想过,当我们对Integer对象进行四则运算的时候,是如何进行的呢?看以下代码:
Integer i = 10;Integer j = 20;System.out.println(i+j);
反编译后代码如下:
Integer i = Integer.valueOf(10);Integer j = Integer.valueOf(20);System.out.println(i.intValue() + j.intValue());
我们发现,两个包装类型之间的运算,会被自动拆箱成基本类型进行。
场景四、三目运算符的使用
这是很多人不知道的一个场景,作者也是一次线上的血淋淋的Bug发生后才了解到的一种案例。看一个简单的三目运算符的代码:
boolean flag = true;Integer i = 0;int j = 1;int k = flag ? i : j;
很多人不知道,其实在int k = flag ? i : j;这一行,会发生自动拆箱。反编译后代码如下:
boolean flag = true;Integer i = Integer.valueOf(0);int j = 1;int k = flag ? i.intValue() : j;
这其实是三目运算符的语法规范:当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。
因为例子中,flag ? i : j;片段中,第二段的i是一个包装类型的对象,而第三段的j是一个基本类型,所以会对包装类进行自动拆箱。如果这个时候i的值为null,那么久会发生NPE。(自动拆箱导致空指针异常)
场景五、函数参数与返回值
这个比较容易理解,直接上代码了:
//自动拆箱public int getNum1(Integer num) {return num;}//自动装箱public Integer getNum2(int num) { return num;}
7、自动拆装箱与缓存
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");}
我们普遍认为上面的两个判断的结果都是false。虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个if判断都是false的。
在Java中,
==比较的是对象应用,而equals比较的是值。
所以,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都将返回false。奇怪的是,这里两个类似的if条件判断返回不同的布尔值。
上面这段代码真正的输出结果:
integer1 == integer2integer3 != integer4
原因就和Integer中的缓存机制有关。在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。
适用于整数值区间-128 至 +127。
只适用于自动装箱。使用构造函数创建对象不适用。
具体的代码实现可以阅读Java中整型的缓存机制一文,这里不再阐述。
我们只需要知道,当需要进行自动装箱时,如果数字在-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语言规范(JLS)规定如下:
如果一个变量p的值是:
-128至127之间的整数(§3.10.1)
true 和 false的布尔值 (§3.10.3)
‘\u0000’至 ‘\u007f’之间的字符(§3.10.4)范围内的时,将p包装成a和b两个对象时,可以直接使用a==b判断a和b的值是否相等。
8、自动拆装箱带来的问题
当然,自动拆装箱是一个很好的功能,大大节省了开发人员的精力,不再需要关心到底什么时候需要拆装箱。但是,他也会引入一些问题。
包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以,但是这个范围之外还是需要使用equals比较。
前面提到,有些场景会进行自动拆装箱,同时也说过,由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。
如果一个for循环中有大量拆装箱操作,会浪费很多资源。常见笔试题:
Integer i1 =59;int i2 = 59;Integer i3 = Integer.valueOf(59);Integer i4 = new Integer(59);System.out.println(i1 == i2); true:包装类和基本类型比较时,包装类自动拆箱为基本类型System.out.println(i1 == i3); true:数值59 在-128到127之间,上文所说的缓存,因此为true,若数值不在-128到127之间则为falseSystem.out.println(i1 == i4); false:引用类型比较地址值,地址值不同System.out.println(i2 == i3); true:i1的源码是i3,i2和i3比较结果和i2与i1比较结果相同,包装类和基本类型比较时自动拆箱System.out.println(i2 == i4); true:包装类和基本类型比较时自动拆箱System.out.println(i3 == i4);同i1 == i4
9、自动拆箱和装箱会影响性能
装箱:原始类型转化为包装类型;如Integer i = 0;java语法默认数值类型为int,0原始类型,i为包装类型,两种不同类型为什么可以赋值呢,这就是因为java做了个自动装箱的操作;拆箱则相反。
例:
上图l = l +1;l+1中l自动拆箱了,所以和是原始类型,后面赋值,和又自动装箱了。不过通过上图发现,好像循环次数少的时候,jvm处理的很快,是不是不用优化了?答案是不是,因为你的程序不止一个人在使用,当很多人调用的时候,积塔成沙,就会很消耗性能。我们减少这种拆箱和装箱,看看优化的效果:
优化后,l + 1里l进行拆箱,发现少了一次自动装箱,对性能影响这么大,还觉得减少自动拆箱和自动装箱过程没用吗?优化从点滴做起。
由此可见,装箱和拆箱/拷贝操作会从速度和内存两个方面损伤应用程序的性能。因此我们应该清楚编译器会在何时自动产生执行这些操作的指令,并使我们编写的代码尽可能减少导致这种情况发生的机会。
所有巧合的是要么是上天注定要么是一个人偷偷的在努力。
结束!
本文转载自【微信公众号:五角钱的程序员,ID:xianglin965】,经微信公众号授权转载,如需转载与原文作者联系
java可以用 lt =判断int吗_int 和 integer:装箱和拆箱的过程,会用到什么方法相关推荐
- java基础语法-day24-25进阶-Arrays工具类String自动装箱自动拆箱
p576 Arrays工具类 p577 冒泡排序 import java.util.Arrays;public class BubbleSort {/*** 冒泡排序:*/public static ...
- Java中的基本类型与封装类型以及自动装箱、拆箱
Java中的类型分为原始类型和对应的封装类型(装箱类型),基本类型包括byte字节型(一个字节).char字符型(两个字节).short短整型(两个字节).int整型(四个字节).long长整型(八个 ...
- Java自动装箱与拆箱
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...
- java 自动装箱自动拆箱
1.Java数据类型 在介绍Java的自动装箱和拆箱之前,我们先来了解一下Java的基本数据类型. 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference ...
- java装箱拆箱_Java中的自动装箱与拆箱
自动装箱和拆箱从Java 1.5开始引入,目的是将原始类型值转自动地转换成对应的对象.自动装箱与拆箱的机制可以让我们在Java的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接. 如 ...
- java byte 判断相等_深入理解Java装箱与拆箱
写给小白看的Java基础知识,阅读本文大概需要7分钟 Java中有8种基础数据类型,boolean,char,byte,short,int,long,float,double.从jdk5开始提供了自动 ...
- java基础第十一篇之Date、Math、自动装箱和拆箱
Date类 表示一个瞬间,就是一个时刻 * * 构造方法: * public Date();//创建一个表示当前系统时间的Date对象 * public Date(long time);//毫秒值,距 ...
- Java的知识点20——包装类基本知识、包装类的用途、自动装箱和拆箱、包装类的缓存问题
包装类基本知识 将基本数据类型存储到Object[]数组或集合中的操作 包装类均位于java.lang包 "数字型"都是java.lang.Number的子类.Number类是抽象 ...
- Java13-day04【Integer、int和String的相转、自动装箱和拆箱、Date、SimpleDateFormat、Calendar、异常、try...catch、throws】
视频+资料(工程源码.笔记)[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg 提取码:zjxs] Java基础--学习笔记(零起点打开java ...
最新文章
- 磁盘占用百分百?Windows 10必做各项优化
- 洛谷P2835 刻录光盘
- Microsoft.CSharp.targets不存在解决方法
- 使用Java制作验证码
- windows11怎么绕过tpm安装,win11在线安装
- python全栈开发_day42_数据库6
- html宽度满屏,宽度满屏的代码怎么样写?
- Vue:进入组件显示蒙版及文字,离开隐藏
- python 水位_python opencv之分水岭算法示例
- 深度学习最基础理论知识总结 (CS231课程总结,持续更新)
- DELL戴尔开启/关闭触摸板方法
- “微肥”还是“歪fai”
- 微信小程序-打开地图选择位置
- XSS绕过,XSS过滤速查,XSS绕过姿势
- 人身三流指什么_什么是“下三流”哪三流,有何解释?
- 广州车展开幕:超定律智能纯电SUV埃安Y全球首发
- 鸿蒙系统桌面搭配,华为平板 MatePad Pro 来了!首搭鸿蒙系统,与电脑“花样”协同…...
- WinRAR的 安装与下载
- 前端学习 Vue笔记 完整版
- CentOS7 初次安装记录(三)配置PHP和MYSQL