通过本质看现象:关于Integer受内部初始化赋值范围限制而出现的有趣现象

简介: Integer源码解析

这是数年前写的第一篇技术文章。

 

前几天我在逛论坛的时候,偶然看到有人讨论这样一个现象,定义四个Integer类型的变量,分别初始化赋值为a=100,b=100,c=1000,d=1000,然后用println分别打印输出a==b和c==d的boolean值。这时就会出现一个很有趣的现象,a==b会被判断为ture,而c==d被判断为false。我觉得这个问题有点意思,自己玩了一遍,运行截图如下:

image.png

     问题便来了,同样类型的数值,为何a==b是正确的,而c==d则被判断为错误。在我们现实生活中,人们总说要透过现象去看本质,但若能反过来通过本质来分析现象,我想,同样可以深入理解很多东西。就像你能读懂一个人,就会很容易理解这个人的所作所为。打一个比方,你要弄懂一个人为何要犯罪,首先得了解他做这件事的心理,这就是通过本质回过头去看现象。

     这道题,如果能通过本质来看现象,就会茅塞顿开。

     Integer的本质是什么,当然是它的源码咯。

   在我们定义Integer a=100时,编译器会转成Integer.valueOf(100),即内部实现是Integer  a= Integer.valueOf(100),而在Integer的源码里valueOf方法如下:

publicstaticIntegervalueOf(inti) {
if (i>=IntegerCache.low&&i<=IntegerCache.high)
returnIntegerCache.cache[i+ (-IntegerCache.low)];
returnnewInteger(i);
}

 


   通过Integer的内部代码,可以看到有一个范围,即IntegerCache.low和IntegerCache.high。通常情况两者默认初始化为IntegerCache.high=127,IntegerCache.low=-128,同时,Integer内部还有一个静态static代码块,它会在类被加载时被执行,该代码块如下:

static {
inth=127;
StringintegerCacheHighPropValue=sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue!=null) {
try {
inti=parseInt(integerCacheHighPropValue);
i=Math.max(i, 127);
h=Math.min(i, Integer.MAX_VALUE- (-low) -1);
                } catch( NumberFormatExceptionnfe) {
                }
            }
high=h;
cache=newInteger[(high-low) +1];
intj=low;
for(intk=0; k<cache.length; k++)
cache[k] =newInteger(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)assertIntegerCache.high>=127;
    }


在执行该静态代码块时,会新建一个数组cache,把-128到127的数字都放在这里面。再结合前面的valueOf方法,可以看出,如果赋值的参数在127个-128之间,就会直接从静态代码块的缓存中返回一个实际数,它们都属于同一个对象;如果超过这个范围,就会return new Integer(i),即返回一个新建且不同的对象值。

   分析完Integer的部分源码后,就可以知道前面问题为何会出现这样的现象了。当a,b赋值为100时,两者都在127~-128的范围间,在同一个缓冲中,属于同一个对象且数值相同,那样a==b即为true;而当c,d赋值为1000时,就超过了范围,就会创建新的对象,两个引用指向不同的对象,即使对象拥有相同的内容,用==比较结果依然是false,这样的话,c,d已不属于同一个对象了,自然就会为false。

 

目录
相关文章
|
6月前
|
C++
成员初始化表的执行顺序与顺写顺序无关
成员初始化表的执行顺序与顺写顺序无关
54 0
|
1月前
|
Java Spring
发现问题就解决,往往是低效的方式。关于对象参数的赋值取值问题
在审查中台task服务代码时,发现TaskVO对象的industryTypeName字段在某些方法调用中未进行空值检查,导致潜在bug。提出两种解决方案:一是在方法③中增加对industryTypeName的空值判断;二是改变方法③的参数类型,避免外部调用方直接设置industryTypeName,从而减少错误发生的可能性。
12 1
|
6月前
|
存储 安全 编译器
C/C++陷阱——临时变量的产生和特性
C/C++陷阱——临时变量的产生和特性
|
6月前
this的含义,什么情况下使用this,改变this指针的两种办法。 === 由于this关键字很混乱,如何解决这个问题
this的含义,什么情况下使用this,改变this指针的两种办法。 === 由于this关键字很混乱,如何解决这个问题
43 0
|
监控 Cloud Native Java
字节码编程,Byte-buddy篇二《监控方法执行耗时动态获取出入参类型和值》
在前面的ASM、Javassist 章节中也有陆续实现过获取方法的出入参信息,但实现的方式还是偏向于字节码控制,尤其ASM,更是需要使用到字节码指令将入参信息压栈操作保存到局部变量用于输出,在这个过程中需要深入了解Java虚拟机规范,否则很不好完成这一项的开发。但!ASM也是性能最牛的。其他的字节码编程框架都是基于它所开发的。
701 0
字节码编程,Byte-buddy篇二《监控方法执行耗时动态获取出入参类型和值》
|
前端开发
前端学习案例3-this指向问题-隐式调用规则
前端学习案例3-this指向问题-隐式调用规则
75 0
前端学习案例3-this指向问题-隐式调用规则
|
前端开发
前端学习案例4-this指向问题-隐式调用规则2
前端学习案例4-this指向问题-隐式调用规则2
73 0
前端学习案例4-this指向问题-隐式调用规则2
如何在把创建临时变量的前提下交换两个数(直接上代码)
如何在把创建临时变量的前提下交换两个数(直接上代码)
|
Python
禁止直接分配给多对多集的正面改用emails_for_help.set()
禁止直接分配给多对多集的正面改用emails_for_help.set()
|
数据库连接 数据库 数据安全/隐私保护
对象变量或with块变量未设置————问题根源
对象变量或with块变量未设置————问题根源
1174 0
对象变量或with块变量未设置————问题根源