java Integer 自动包装与解包

关于java的自动包装机制想必大家都用过吧,一般这些机制都用于在往容器中存储基本类型数据的时候,因为容器中不允许存在基本数据类型,所以就会调用自动包装机制,将基本数据类型转换为对象,将基本数据保存在对象中,并且提供一些基本方法,但是自动包装机制存在一些陷阱,使用不当就会出错

先看看下面一个例子吧

 1 package test;
 2 
 3 public class AutoPack {
 4     public static void main(String[] args) {
 5         Integer a=1;
 6         Integer b=2;
 7         Integer c=3;
 8         Integer d = 3;
 9         Integer e=321;
10         Integer f=321;
11         Long g=3L;
12         System.out.println(c==d);//true
13         System.out.println(e==f);//false
14         System.out.println(c==(a+b));//true
15         System.out.println(c.equals(a+b));//true
16         System.out.println(g==(a+b));//true
17         System.out.println(g.equals(a+b));//false  //不是同一类型
18         System.out.println(g.equals((long)(a+b)));//true   首先比较是不是同一类型,再比较值
19     }
20 }

上面例子中的输出你都做对了吗?如果有疑惑,请看我下面的解答

首先我们得请出一个前提:对于对象类型,==符号表示比较对象的所在的物理地址,equals方法比较的是对象的值(前提是两者属于同一个对象类型),而对于基本数据类型,==符号比较的是值

然后我们再来看一看Integer的内部实现,Integer有三种创建方法,分别是

Integer a = new Integer(1);  //创建新的类

Integer b = Integer.valueOf(2);  

Integer c = 3;    //自动包装,会调用valueOf方法

上面的三种方法中,第一种方法所创建的是一个全新的Integer对象,这样的对象在用 == 比较时是肯定不相同的,只能通过 equals 方法进行比较

,第二种方法和第三种方法都显式或者隐式的调用了ValueOf方法,所以下面我们来看一下ValueOf方法

   public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

valueOf方法首先判断数字是否大于low(-128)并且小于数字(127),如果满足条件,则直接从IntegerCache中返回这个数(IntegerCache用于存储一些常用的数,防止重复创建),

所以只要是用 valueOf 或者Integer = num 这两种方法创建的对象,其值小于127且大于-128的,无论对其进行 == 比较还是equals 比较,都是true

对于不满足这个范围的数,无论怎么创建,都是一个新的对象,是只能通过equals比较的,接下来我们再看看equals方法

 

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

equals很简单,首先比较两者的类型是否一致,如果类型不一致,直接返回false,否则,再比较两者的值,相同则返回true

那么现在你再回过头去看上面的输出,是不是清晰明了呢

还有一点就是上面的第三个和第五个输出了,因为等式两边都运用了算术运算符,所以会自动拆包,拆包后比较的就是两者的value了

 

那么下面来总结一下:

1.在==运算的时候,如果两端中任何一端含有算术表达式,就会发生自动解包,这时比较的是值

2.在==运算时,两端都没有算术表达式,就不会解包,这时比较的是对象的地址(这样使用很危险)

3.equals可以比较对象的值,比较推荐使用,但前提是要相同对象类型,比如在上面倒数第二个输出中,虽然值相等,但是一个是Integer,一个是Long,就会返回false,但是如果是基本数据类型int 和 long ,他们其实是可以相等的

4.Integer中有IntegerCache,会对-128到127的值进行缓存,所以在这个范围内只要不用new 关键字创建Integer对象,那么这些对象都是同一个对象

posted @ 2019-05-04 11:54  流浪猿球  阅读(1591)  评论(0编辑  收藏  举报