Java中Integer和int的区别解读
作者:理想万岁万万岁
一、介绍
各位小伙伴们无论在工作还是学习中,与Integer都有着过硬的交情,我说的没错吧,大家都知道他可以表示一个整数,而且也知道可以表示整数的还有int,只是使用Integer的次数要比int多得多,今天我们就来好好探究一下Integer与int的区别以及更深处的知识。
二、不同点
Integer是包装类型(即引用类型),int是基本类型。
也就是说,Integer是一个类,里面有很多方法可以使用,例如
boolean equals(Object obj){...} int compareTo(Integer anotherInteger){...}
而int不是一个类,能做的只有+、-、*、/、=五种运算,例如
int a = 3; int b = 4; int c = a + b;
Integer的默认值是null,int的默认值是0
Integer变量使用之前必须先实例化,int变量可以直接使用。
Integer如果没有实例化就直接使用会报空指针异常(因默认值为null);int如果没有初始化则使用默认值0。
三、相同点
取值范围相同
最小值:Integer.MIN_VALUE= -2147483648 (-2的31次方)
最大值:Integer.MAX_VALUE= 2147483647 (2的31次方-1)
原因:众所周知,整型变量在内存中的字节数是4个字节,一个字节是8位,因此一个整型变量占据32位,且首位为0表示非负数,1表示负数。
四、使用equals()和==的区别
对于每个java开发人员来说,Integer的用法再熟悉不过了,但仍然会有些工作一两年的小伙伴依然搞不清楚不同情况下equals()方法和 == 等号究竟有什么结果,以至于在基础的面试过程中翻跟头体验屡试不爽。这次我们一次性把所有可能以及结果出清楚。
equals()
此方法由Object类定义,在Integer类中又对其进行了重写,我们来看一下重写后的方法。
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
这个方法先判断参数对象是否继承了Integer引用类型(如果参数是int基本类型,会先将其自动装箱成引用类型),如果没有继承Integer引用类型,则返false,这个很好理解,如果数字和字符相比,那叫什么事嘛。如果继承了Integer引用类型,就先把它强转成Integer类型,再通过intValue()方法将其拆箱为int基本类型,再和value进行地址比较(==右边的value表示的是此Integer对象在常量池中的值,该值其实也是及本来想常量)。
说了一大堆,简单一句话就是equals()方法进行的是常量池中的地址是否相等。
另外一点:常量池中值相等的数据不会同时出现,常量池中只保存一份相同的值。
==
比较两个对象在内存中的地址是否相等。
下面是我们使用equals()方法和==方法来判断Integer和int的区别。在此之前,我们要先知道装箱和拆箱、常量池对象和堆内存对象两个概念:
装箱
将基本数据类型变成引用类型的过程。发生在将基本数据类型赋值给引用类型的时候, 如Integer i = 5;
拆箱
将引用类型变成基本数据类型的过程。发生在将引用类型和基本数据类型做运算的时候,如下所示
Integer i = 5; int j = 5; System.out.println(i==j);
常量池对象
保存的是创建对象时的字面量,相等的字面量只保存一次
堆内存对象
保存的是new一个对象时这个对象在堆内存中的地址
声明变量 | 使用equals()方法比较 | 使用==比较 | |
1 | Integer i = new Integer(1); Integer j = new Integer(1); | true | false |
2 | Integer i = new Integer(1); Integer j = 1; | true | false |
3 | Integer i = new Integer(1); int j = 1; | true | true |
4 | Integer i = 1; Integer j = 1; | true | true |
5 | Integer i = 1; int j = 1; | true | true |
6 | int i = 1; int j = 1; | —— | true |
7 | Integer i = new Integer(128); Integer j = new Integer(128); | true | false |
8 | Integer i = new Integer(128); Integer j = 128; | true | false |
9 | Integer i = new Integer(128); int j = 128; | true | true |
10 | Integer i = 128; Integer j = 128; | true | false |
11 | Integer i = 128; int j = 128; | true | true |
12 | int i = 128; int j = 128; | —— | true |
情况1
在Integer i = new Integer(1)的过程中,java为我们做了两件事,先在常量池中创建一个int=1的常量,再在堆内存中创建一个对这个常量的地址引用,因此在用equals()方法时比较的是常量池中int=1这个常量,自己和自己比较的结果当然为true;
而在==运算时,直接比较了堆内存中的地址,于是比较的结果为false
情况2
在Integer j = 1的过程中,实际上是java为我们在常量池中生成了一个常量对象1,然后j对象指向这个常量对象的地址。
equals()运算结果为true是因为比较的是常量池中对象的比较,实际上常量池中只有一个值为1的对象,即自己比较自己。
==运算结果为false是因为比较的是堆内存中对象j的地址和常量池中常量对象1的地址,是两个不同的地址比较
情况3
equals()运算结果为true可以参考上面的源码以及下方解释
==运算结果为true是因为引用类型Integer和基本数据类型int比较时,引用类型会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较,也是堆内存中常量自己与自己的地址比较
情况4
变量i与变量j指向的其实都是常量池中的常量对象1,因此equals()运算和==运算的结果都是true
情况5
与情况4相同, 如果有疑惑可在文章后面查找答案
情况6
基本数据类型只能进行加、减、乘、除、等于五种运算,没有equals()方法,==运算为true还是因为堆内存中常量自己与自己进行地址比较。
情况7
new Integer(128)会先在常量池中创建一个常量对象128,再在堆内存中保存这个常量对象的地址,Integer i = new Integer(128)中变量i指向堆内存中保存这个常量对象地址的地址,它是指向堆内存的。可以理解为两个不同的堆内存地址指向相同的常量池地址。
equals()运算结果为true是因为比较的是常量池中的地址,而该地址只有一个,自己比较自己,结果为true
==运算比较的是这两个堆内存的地址,因此结果为false
情况8
equals()运算结果为true说了很多遍了,都是同一个原因
==运算为false是因为比较的是堆内存中两个对象的地址,原因和情况5相同,可在文章后面查找答案
情况9
与情况3相同
情况10
与情况8相同,可在文章后面查找答案
情况11
与情况3相同
情况12
与情况6相同
五、解惑
JVM中一个字节一下的整型数据(即[128,127])会在JVM启动时加载进内存,除非用new Integer()显示的创建对象,否则都是同一对象。当使用Integer i = 1时,会将1这个数字进行缓存,下次再运行Integer j = 1时,就会直接从缓存中取,就不会new了, 这样取到的1 地址也是相同的, ==判断返回true。
对于-128 ~ 127范围之外的数 实际上就是new得到的, 地址不同==判断为false
java在编译Integer i = 100 ;时,java内部会将其翻译成为Integer i = Integer.valueOf(100);
所以关键就是看valueOf()函数了。JDK源码的valueOf()是这样的
到此,Integer与int运算时的迷之操作总算解释清楚了,如果有需要指正或者补充的,请小伙伴们扫下方二维码关注公众号并在后台留言,我会及时给予回复,让我们一起把java学到荒,头发掉到光。
到此这篇关于Java中Integer和int的区别解读的文章就介绍到这了,更多相关Integer和int的区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!