文章目录
- 一、介绍
- 二、不同点
- 三、相同点
- 四、使用`equals()`和`==`的区别
- 五、解惑
一、介绍
各位小伙伴们无论在工作还是学习中,与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学到荒,头发掉到光。
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————