由装箱引起的——Integer比较的前因后果

前置知识:两个对象==比较的是栈的值,"==" 在java中比较对象时永远是比较对象的地址,这一点毫不会错。众所周之,java是保留了int,char等基本数据类型的,也就是说int类型的并非对象,然而有些方法却须要object 类型的变量,因此java使用了装箱机制,咱们能够自豪的这样声明一个整型变量:Integer a = new Integer(10); 那么整型的a也就是对象了,那这句是什么意思呢:Integer a= 10; java中能够这样声明一个对象吗?固然不是,从jdk1.5后,java实现了自动装箱,也就是自动将Integer a =10 中的int类型的10转化为了 Integer类型。 java

好,有了前面的只是咱们且先看一个题目:
Integer a = 127;
Integer b = 127;

Integer c = 128;
Integer d = 128;

System.out.println(a==b);
System.out.println(c==d); 数组

答案是什么呢? 若是您回答true,false,那么很遗憾的告诉你,你答对了!!! 缓存

分析一下,Integer a =127,Integer a=128。127,128应该不会形成什么差别吧,难道是自动装箱的过程有猫腻?找下源码看看:
private static class IntegerCache {
    private IntegerCache(){
    }
    static final Integer cache[] = new Integer[-(-128) + 127 + 1]; jvm

    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Integer(i - 128);
        }
    }
    public static Integer valueOf(int i) {
        final int offset = 128;
        if (i >= -128 && i <= 127) { // must cache
            return IntegerCache.cache[i + offset];
        }
        return new Integer(i);
    }
}
spa

源码解释:当咱们装箱时,jvm其实是自动调用的valueOf()这个方法,也就是Integer a= 10至关于Integer.valueOf(10)。好,咱们看下Integer a = 127 的执行过程,首先调用Integer.valueOf(127) ,因为127在-128到127之间(看上面的源码),因此返回一个缓存值 return IntegerCache.cache[127+128];也就是数组中下标是255的值,那这个究竟是什么值呢? 咱们继续看: 对象


static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Integer(i - 128);
    } 内存

这是用一个for循环对数组cache赋值,cache[255] = new Integer(255-128),也就是new一个Integer(127) ,并把引用赋值给cache[255],好了,而后是Integer b= 127,流程基本同样,最后又到了cache[255] = new Integer(255-128),这一句,有点迷糊了,这不是又new了一个对象127吗,而后把引用赋值给cache[255],咱们比较这两个引用(前面声明a的时候也有一个),因为是不一样的地址,因此确定不会相等,应该返回false啊!这么想你就错了,请注意看for语句给cache[i]初始化的时候外面有一个{},{}前面一个大大的static关键字大咧咧的杵在哪呢,对静态的,那么咱们就能够回想下static有什么特性:
只能初始化一次,在对象间共享,也就是不一样的对象共享同一个static数据,那么当咱们Integer b = 127的时候,并无new出一个新对象来,而是共享了a这个对象的引用,记住,他们共享了同一个引用!!!,那么咱们进行比较a==b时,因为是同一个对象的引用(它们在堆中的地址相同),那固然返回 true了!!! 源码

而后咱们在看Integer c = 128;Integer d = 128;,当数据再也不-128到127之间时,是不执行return IntegerCache.cache[i + offset];这句的,也就是不会返回一个static的引用,而是执行了return new Integer(i); 因而当 Integer d = 128 时,又会从新返回一个引用,两个不一样的引用
在作c==d 的比较时固然返回false了!! for循环

/*===========================================================*/ class

public static void main(String[] args) {
    Integer a = new Integer(1);
    Integer b = new Integer(1);
    int c=1;
    Integer e = 1;
    System.out.println("a==b:"+(a==b));
    System.out.println("a==c:"+(a==c));
    System.out.println("a==e:"+(a==e));
    System.out.println("c==e:"+(c==e));
}
结果:
a==b:false
a==c:true
a==e:false
c==e:true

Integer是int的封装对象,两个对象==比较的是栈的值。
Integer a = new Integer(1);
Integer b = new Integer(1);
a与b在栈中,存的是Integer对象在堆中的地址,而不是值。
a、b指向堆中的地址显然不一样因此 a==b 为false.


int c = 1; int为值类型,引用类型Integer与值类型int比较显然比较的是值。
由于int在堆中是不开辟内存的,他在栈中的值则为他自己的值
因此a==c比较的是他们各自的value, a==c为true

Integer e=1; 这个比较特殊,直接赋值,它有独立的内存,每次赋值时将检查内存中是否有值跟他匹配的,如有则把此内存地址付给e,若没有,开辟新的内存。

你能够尝试下面的例子:
Integer t1 = 1;
Integer t2 = 1;
t1==t2 为true,如上所说,此时t1与t2指向的是同一块内存。

new 必定是开辟新的内存,直接赋值则不必定开辟新的内存。
由于a的引用指向堆,而e指向专门存放他的内存,因此他们的内存地址不同。
因此a==e为false.

c==e等同于 a==c,一个引用类型一个值类型
integer与integer比较的是引用的地址,integer与int,integer先拆箱,比较的是值。

/*==========================================================*/

Integer 在自动装箱时调用了valueOf() 方法,其中IntegerCache 用来缓存Integer值的。默认缓存的Integer 值范围是  -128 ~ 127 。
 
咱们来分析一下valueOf(int i)的执行过程:
若是 i 大于缓存中的 最小值(-127) 而且 小于 缓存中的最大值(127),直接返回IntegerCache 中缓存的Integer对象。不然就新建一个Integer对象并返回。

在-128~127之间时,装箱操做后,a 和 b 都是指向缓存中的同一个对象,结果返回true。其余状况下就不同了,装箱操做时都是返回新的Integer对象,== 操做时地址必然不相等,因此返回false。   之后遇到数字比较时,要么先将值赋给对应的基本类型在比较,要么比较包装类型中的包装值(例如 a.intValue() == b.intValue()),要么直接调用equals方法。

相关文章
相关标签/搜索