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

文/朱季谦

这是我很多年前的第一篇技术博客,当时作为一名技术小菜鸟,总体而言显得很拙见,但也算是成长路上的一个小脚印,希望能在以后的日子里,可以对JAVA技术有一个更加深入的思考与认识。

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

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

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

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

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

java 复制代码
    public static Integer valueOf(int i) {

        if (i >= IntegerCache.low && i <= IntegerCache.high)

          return IntegerCache.cache[i + (-IntegerCache.low)];

          return new Integer(i);

}

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

java 复制代码
    static {
             int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                }
            }
            high = h;
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.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。

相关推荐
开心工作室_kaic6 分钟前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王8 分钟前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康13 分钟前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神1 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
qq_327342731 小时前
Java实现离线身份证号码OCR识别
java·开发语言
阿龟在奔跑2 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
飞滕人生TYF2 小时前
m个数 生成n个数的所有组合 详解
java·递归
代码小鑫3 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖3 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶3 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka