转自:java
https://blog.csdn.net/xingkongdeasi/article/details/79618421程序员
部分有所修改:缓存
前言:.net
越是简单的东西,咱们每每越是没有去把它明白,但咱们大部分时间又经常在用,就像咱们今天说的int与Integer的使用,咱们程序员基本每天都在用,可是我今天没用详细弄清楚以前我也是不清楚,咱们来看看这两个在用==号比较给咱们带来的疑问。对象
先看看下面的代码,看看咱们是否都会blog
@Test
public void testEquals() {
int int1 = 12;
int int2 = 12;
Integer integer1 = new Integer(12);
Integer integer2 = new Integer(12);
Integer integer3 = new Integer(127);
Integer a1 = 127;
Integer a2 = 127;
Integer a = 128;
Integer b = 128;
System.out.println("int1 == int2 -> " + (int1 == int2));
System.out.println("int1 == integer1 -> " + (int1 == integer1));
System.out.println("integer1 == integer2 -> " + (integer1 == integer2));
System.out.println("integer3 == a1 -> " + (integer3 == a1));
System.out.println("a1 == a2 -> " + (a1 == a2));
System.out.println("a == b -> " + (a == b));
} 内存
答案是:
一、 int1 == int2 -> true
二、 int1 == integer1 -> true
三、 integer1 == integer2 -> false
四、 integer3 == a1 -> false
五、 a1 == a2 -> true
六、 a == b -> false
看看结果跟咱们本身作的是否是都同样。test
下面咱们就来详细解释一下,为何是上面的结果。(下面的序号就是对应的是上面的答案序号)变量
一、int1 == int2 为true,这个我就讲了,这个都知道程序
二、int1 == integer1,Integer是int的封装类,当Integer与int进行==比较时,Integer就会拆箱成一个int类型,因此仍是至关于两个int类型进行比较,这里的Integer,不论是直接赋值,仍是new建立的对象,只要跟int比较就会拆箱为int类型,因此就是相等的。
三、integer1 == integer2 -> false,这是两个都是对象类型,并且不会进行拆箱比较,因此不等
四、integer3 == a1 -> false , integer3是一个对象类型,而a1是一个常量它们存放内存的位置不同,因此也不等,具体存在内存的位置看以看文章:点击打开连接
五、6 看起来是如出一辙的为何一个是true,一个是false,这是由于Integer做为常量时,对于-128到127之间的数,会进行缓存,也就是说int a1 = 127时,在范围以内,这个时候就存放在缓存中,当再建立a2时,java发现缓存中存在127这个数了,就直接取出来赋值给a2,因此a1 == a2的。当超过范围就是new Integer()来new一个对象了,因此a、b都是new Integer(128)出来的变量,因此它们不等。
根据以上总结:
①、不管如何,Integer与new Integer不会相等。不会经历拆箱过程,由于它们存放内存的位置不同。(要看具体位置,能够看看这篇文章:点击打开连接)
(Arnold备注:new Integer()必然是堆内存中新增数据,Integer 是java的常亮实现类,若是是在-128到127时则存在于常量池中,若是大于127,则在堆内存中新增对象,==比较的为内存地址,因此即便
new Integer() 和直接使用Integer 定义数据,都是在堆内存中存储的数据,则对应的内存地址也不会相同,因此,new Integer 于 Integer 必然不会相等)
②、两个都是非new出来的Integer,若是数在-128到127之间,则是true,不然为false。
③、两个都是new出来的,则为false。(备注:除了进入常量池的对象,在实例化前会去常量池中比较是否有相同的内容,相同则返回当前常量池的内存地址,其他进入堆内存空间的对象,一概是直接开辟空间进行堆内存的存储,不会进行是否已经存在的判断)
④、int和integer(new或非new)比较,都为true,由于会把Integer自动拆箱为int,其实就是至关于两个int类型比较。(备注:两个int 的比较操做,实际就是直接进行值的比较的操做)
(Arnold备注:方法区常量池的概念此处再也不赘述,此处主要说明下,java中常量池对基本类型的一些实现:)
Java中实现常量池的基本类型的包装类分别是:String,Byte,Short,Integer,Long,Character,Boolean,浮点数的包装类型则没有实现,Byte,Short,Integer,Long,Character 五中类型
也只是在对应的值小于 127和-128时才会实现常量池,超出该值的范围则直接在堆内建立内存,于上述介绍的Integer的常量池一致,而对于String的常量池则和上面所提到的其余类型的常量池基本一致,
对于直接String =“”“” 来建立的对象数据则是直接存储在常量池中,没有大小和范围的限制,而对于直接 使用 new 的方式建立的对象,则都会直接放到堆内存中,此处于其他的常量池的实现类是一致的。
可参考以下连接:https://blog.csdn.net/qiaoijun/article/details/48878039
String s = "Java" 这种声明的方式。产生的这种"常量"就会被放到常量池,常量池是JVM的一块特殊的内存空间。使用Java常量池技术,是为了方便快捷地建立某些对象,当你须要一个对象时候,就去这个池子里面找,找不到就在池子里面建立一个。可是必须注意 若是对象是用new 建立的。那么不论是什么对像,它是不会放到池子里的,而是向堆申请新的空间存储。java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型