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对象,那么这些对象都是同一个对象