龙空技术网

阿里巴巴java为什么整型包装类对象值强制用equals方法比较?

IT大派 194

前言:

现在你们对“java输入函数整形”都比较注重,咱们都需要剖析一些“java输入函数整形”的相关内容。那么小编在网络上收集了一些关于“java输入函数整形””的相关资讯,希望小伙伴们能喜欢,同学们一起来学习一下吧!

在阅读《阿里巴巴Java开发手册》时,发现有一条关于整型包装类对象之间值比较的规约,具体内容如下:

这条建议非常值得大家关注, 而且该问题在 Java 面试中十分常见。

还需要思考以下几个问题:

如果不看《阿里巴巴Java开发手册》,如何知道 Integer var = ? 会缓存 -128 到 127 之间的赋值?为什么会缓存这个范围的赋值?如何学习和分析类似的问题?Integer 缓存问题分析

先看下面的示例代码,并思考该段代码的输出结果:

测试Integer的缓存机制

结果输出:

那么为什么答案是这样?

结合《阿里巴巴Java开发手册》的描述很多人可能会回答:因为缓存了 -128 到 127 之间的数值,就没有然后了。

那么为什么会缓存这一段区间的数值?缓存的区间可以修改吗?其它的包装类型有没有类似缓存?

接下来,让我们一起进行分析。

源码分析法

首先我们可以通过源码对该问题进行分析。

我们知道,Integer var = ? 形式声明变量,会通过 java.lang.Integer#valueOf(int) 来构造 Integer 对象。

怎么知道会调用 valueOf() 方法呢?

大家可以通过打断点,运行程序后会调到这里。

先看 java.lang.Integer#valueOf(int) 源码:

通过源码可以看出,如果用 Ineger.valueOf(int) 来创建整数对象,可以看出当i在一个范围内时,会从一个Integer[]数组中取出一个Integer对象。所以我们就知道为什么某些时候==是不会出错的。那么接着我们来分析其实际范围是多少,合适加载这些缓存。

那么接着我们来分析其实际范围是多少,合适加载这些缓存。

IntegerCache内部类

可以看出Integer缓存默认范围是-128<—>127,可以通过IntegerCache.high设置最大的范围。因为这部分是static的,所以在加载类是就会初始化Integer缓存,之后只要符合范围内所有Integer都是来自于这个缓存数组static final Integer cache[]。

这给我们一个非常重要的启发:

如果想减少内存占用,提高程序运行的效率,可以将常用的对象提前缓存起来,需要时直接从缓存中提取。

那么为什么会缓存这一段区间的数值?缓存的区间可以修改吗?其它的包装类型有没有类似缓存?

接下来,让我们一起进行分析。

可以看到,hign的值,默认是127, 如果java.lang.Integer.IntegerCache.high的变量有设置,则取这个值。jvm再初始化的时候,会将低值(-128)到高值(默认127)之间的数字加载到内存中。

不知道有没有注意到: 低值是固定的,不能改变,只能是-128,但是高值是可以通过jvm参数改变的~

So,如果业务场景下,需要将高值变更怎么设置呢?

在java程序执行的时候加上 -XX:AutoBoxCacheMax=<size> 的参数即可~~ 可以尝试下设置成200,那么上面的demo栗子的中的结果会变化哦,或可以通过虚拟机参数 -Djava.lang.Integer.IntegerCache.high=<value> 来设置的,未指定则为 127。

反编译法

那么究竟 Integer var = ? 形式声明变量,是不是通过 java.lang.Integer#valueOf(int) 来构造 Integer 对象呢? 总不能都是猜测 N 个可能的函数,然后断点调试吧?

如果遇到其它类似的问题,没人告诉我底层调用了哪个方法,该怎么办?

这类问题,可以通过对编译后的 class 文件进行反编译来查看。

首先编译源代码:javac IntegerTest.java

然后需要对代码进行反编译,执行:javap -c IntegerTest

如果想了解 javap 的用法,直接输入 javap -help 查看用法提示(很多命令行工具都支持 -help 或 --help 给出用法提示)

反编译后,我们得到以下代码:

很明显 四个Integer对象的构造使用了java/lang/Integer.valueOf函数。

再看一个例子:

首先,7行和8行输出结果都为true,因为Integer和int比都会自动拆箱(jdk1.5以上)。

12行的结果为true,而15行则为false。java在编译Integer i5 = 127的时候,被翻译成-> Integer i5 = Integer.valueOf(127);所以关键就是看valueOf()函数了。只要看看valueOf()函数的源码就会明白了。

理论上讲,当系统需要频繁使用Integer时,或者说堆内存中存在大量的Integer对象时,可以考虑提高Integer缓存上限,避免JVM重复创造对象,提高内存的使用率,减少GC的频率,从而提高系统的性能。

对于以上的情况总结如下:

无论如何,Integer与new Integer不会相等。不会经历拆箱过程,i3的引用指向堆,而i4指向专门存放他的内存(常量池),他们的内存地址不一样,所以为false两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存两个都是new出来的,都为falseint和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比

标签: #java输入函数整形