天天看点

浅谈Integer

今天看到这样一道题;

class AutoUnboxingTest {

    public static void main(String[] args) {
        Integer a = new Integer(3);
        Integer b = 3;                  // 将3自动装箱成Integer类型
        int c = 3;
        System.out.println(a == b);     // false 两个引用没有引用同一对象
        System.out.println(a == c);     // true a自动拆箱成int类型再和c比较
    }
}
           

从jdk5开始引入了装箱、拆箱机制,关于Integer中的==,jdk源代码是这样写的:

* @since  1.5
     */
    public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
           

上面这段代码首先规定了一个范围,默认是-128-127之间,如果参数中的i在这个范围之内,则返回一个数组中的内容,如果不在这个范围,则new一个新的Integer对象并返回。查看Integer类的源码可以发现,这个数组里面缓存了基本类型-128-127之间的Integer对象。显然:Integerb=3 是将3自动转型了,而a是直接new了一个对象,开辟了一块新的堆空间,所以他们的指向地址肯定是不相等的。

在Integer常量池中,Integer只对包装了int值在-128-127这个范围的Integer对象做了共享。这种共享模式叫做享元模式,在所有设计模式中都有各自的优点和缺点,享元模式也不例外。享元模式它的优点在于,通过共享一些对象降低内存中相同对象的数量。

但是,想象一下int类型从0x80000000到0x7fffffff如果把所有这些数字包装成共享对象,那需要的对象的数量将是多么的庞大,恐怕还不如不进行处理呢,另外在程序中有很多用不上(在项目中从来那没见那个程序会把所有的int值用个遍的)。

因此Integer只对包装了int值在-128-127这个范围的Integer对象做了共享。如果超过了这个范围,就会在堆空间上开辟一个新的区域(return new Integer(i);)

再来一道题:

public static void main(String[] args) {
        Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;

        System.out.println(f1 == f2);
        System.out.println(f3 == f4);
    }
           

   f1==f2,这里会给f2自动装箱,因为是在-128-127之间,所以不用new新的对象了,直接引用常量池的对象。故他们指向的是同一个对象,是true;    f3==f4,f3 f4不在-128-127之间,所以各自在堆中开辟新的空间,指向的不是同一对象,为false。

总结    Object类中的equals方法和“==”是一样的,没有区别,而String类,Integer类等等一些类,是重写了equals方法,才使得equals和“==不同”,“==比较地址,equals比较值”。    但是对于包装类和基本类型,还要涉及它们的自动装箱、自动拆箱,所以小心一点还是比较好的,不要走到别人挖的陷阱中。

继续阅读