概述
在判断两个Integer是否相等的时候我们一般都是使用equals
来比较是否相等,很多网上的博客也有提到过两个Integer的值在[-128, 127] 之间的时候,可以直接通过==
来比较是否相等。那么为什么[-128, 127] 之间的Integer可以直接用==
呢?
从自动装箱说起
public class Demo {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
System.out.println(i1 == i2);
//输出true
i1 = 1000;
i2 = 1000;
System.out.println(i1 == i2);
//输出false
}
}
实际上,这段代码在JDK1.5之前是不合法的,因为代码中的100是个int类型,属于Java中的8种基本类型之一,而Integer是个对象,对象怎么能等于一个基本类型呢?所以在JDK1.5之前要声明一个值为100的Integer,正确的写法是:Integer i = new Integer(100)
或 Integer i = Integer.valueOf(100)
而在JDK1.5之后,编译器提供了自动拆箱和装箱的功能,Integer i = 100
正是编译器帮我们自动装箱了。
那么我们看看上面代码的编译后是什么样子。借助jd-gui这个工具,我们将.class文件反编译出来。
可以看见编译后的代码其实是由编译器用Integer.valueOf
帮我们将基本类型装箱了。
不简单的valueOf
让我们来看看valueOf
的源代码
valueOf
方法上面的注释说明的非常明白,这个方法会将传入的int值包装成Integer对象返回,这个方法默认会缓存-128到127的值,也可能缓存这个范围外的值。
再来看看方法中的逻辑,这个方法会判断传入的int值是否在IntegerCache
的最高值和最低值之间,如果在这个之间,就会从IntegerCache
的缓存中获取Integer对象,否则就会new一个新的Integer对象。
我们通过debug看一下IntegerCache.cache
里面到底有什么
IntegerCache.cache
中的元素是-128到127顺序排列在数组的0-256位置,假设我们传入的i = -128,通过寻址公式计算下标
i + (-IntegerCache.low) = -128 + (128) = 0
而下标0的元素刚好就是-128。这个寻址公式还挺巧妙的,设计者真是个天才。
思考最初的问题
到了这一步我们就可以明白了:为什么当Integer的值为 [-128, 127] 时,用==
判断两个两个值相等的Integer可以得到true,而超出这个范围后,用 ==
判断两个两个值相等的Integer却得到false?因为当值在[-128, 127] 之间时,valueOf
方法不会创建新的Integer对象,而是从缓存中获取,这样一来,值相同的int,计算所得的下标是一样的,自然会获取到同一个Integer对象。而超出这个范围就不会从缓存中获取了,每次都new一个新的Integer对象,两个不同的对象的内存地址不同,用==
自然会得到false。
静态内部类IntegerCache
在明白了装箱的原理后,我们不妨看一看IntegerCache
的缓存是如何初始化的。
初始化缓存的过程如下
- 获取JVM的中的参数
java.lang.Integer.IntegerCache.high
,将其转为int类型,作为high的值 - 计算
high
与low
之间的差值并+1作为缓存数组的长度 - 从-128开始连续递增,给缓存数组的每个位置设置Integer对象。
以上就是缓存初始化的步骤。
另外,java.lang.Integer.IntegerCache.high
的值默认是127,但是我们可以在程序启动时通过启动参数对其进行设置。
网上都说用-Djava.lang.Integer.IntegerCache.high=<size>
来修改,但是我看到类上的注释推荐我使用-XX:AutoBoxCacheMax=<size>
来修改。亲自试了一下,两种参数都可以成功修改。
将缓存最大值改成1000后,再次测试一下最开始的那段代码
此时两个输出都为true。
最后
以上就是懦弱人生为你收集整理的Integer中为什么-128~127之间的值可以直接==的全部内容,希望文章能够帮你解决Integer中为什么-128~127之间的值可以直接==所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复