今天跟大家聊一个有趣的话题,在Java中两个Integer对象做比较时,会产生意想不到的结果。
例如:
Integer?a?=?100;
Integer?b?=?100;
System.out.println(a==b);
其运行结果是:true。
而如果改成下面这样:
Integer?a?=?1000;
Integer?b?=?1000;
System.out.println(a==b);
其运行结果是:false。
看到这里,懵了没有?
为什么会产生这样的结果呢?
上面例子中的a和b,是两个Integer对象。
而非Java中的8种基本类型。
8种基本类型包括:
byte
short
int
long
float
double
boolean
char
Integer其实是int的包装类型。
在Java中,除了上面的这8种类型,其他的类型都是对象,保存的是引用,而非数据本身。
Integer?a?=?1000;
Integer?b?=?1000;
可能有些人认为是下面的简写:
Integer?a?=?new?Integer(1000);
Integer?b?=?new?Integer(1000);
这个想法表面上看起来是对的,但实际上有问题。
在JVM中的内存分布情况是下面这样的:
在栈中创建了两个局部变量a和b,同时在堆上new了两块内存区域,他们存放的值都是1000。
变量a的引用
指向第一个1000的地址。
而变量b的引用
指向第二个1000的地址。
很显然变量a和b的引用不相等。
既然两个Integer对象用==号,比较的是引用是否相等,但下面的这个例子为什么又会返回true呢?
Integer?a?=?100;
Integer?b?=?100;
System.out.println(a==b);
不应该也返回false吗?
对象a和b的引用不一样。
Integer?a?=?1000;
Integer?b?=?1000;
其实正确的简写是下面这样的:
Integer?a?=?Integer.valueOf(1000);
Integer?b?=?Integer.valueOf(1000);
在定义对象a和b时,Java自动调用了Integer.valueOf
将数字封装成对象。
而如果数字在low和high之间的话,是直接从IntegerCache
缓存中获取的数据。
Integer类的内部,将-128~127之间的数字缓存起来了。
也就是说,如果数字在-128~127,是直接从缓存
中获取的Integer对象。如果数字超过了这个范围,则是new
出来的新对象。
文章示例中的1000,超出了-128~127的范围,所以对象a和b的引用指向了两个不同的地址。
而示例中的100,在-128~127的范围内,对象a和b的引用指向了同一个地址。
所以会产生文章开头的运行结果。
为什么Integer类会加这个缓存呢?
答:-128~127是使用最频繁的数字,如果不做缓存,会在内存中产生大量指向相同数据的对象,有点浪费内存空间。