我们可能从书上能看到,所有整型包装类对象之间值的比较,全部使用equals进行比较,那么为什么不能用 "==" 比较呢?我们先看下面的例子。
Example1:
public class Demo3 { public static void main( String[] args ) { Integer a = 2; Integer b = 2; System.out.println(a == b);//保存的是地址 }}
Example2:
public class Demo3 { public static void main( String[] args ) { Integer a = 222; Integer b = 222; System.out.println(a == b);//保存的是地址 }}
通过测试Example1 的结果为 True;
Example2的结果为false;
那么为什么呢?
下面先看下字节码:
我们看到划线的部分:
Integer i = 2;会自动装箱,调用Integer.valueOf()方法进行转换。
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
static final int low = -128;IntegerCache.high >= 127
也就是说,如果Integer的范围在 -128~127之间,则调用valueOf方法时,会从缓存中获取。
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property 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); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } 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; } private IntegerCache() {} }
那么为什么Example1为true呢?
Integer a = 2;
Integer b = 2;
都是从缓存中获取相同的对象。
那么为什么Example2为false呢?
Integer a = 222;//new Integer(222)
Integer b = 222;//new Integer(222)
a== b 比较的是地址,所以为false;
所以说对Integer 进行值比较时,需要用equals方法
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
分享一个面试题
面试题:
主方法定义两个Integer变量,并赋值
然后通过一个swap方法交换变量的值
请写出swap方法的实现
实现程序如下:
public class Demo { //java中的传值方式 按值传递 引用传递 public static void main( String[] args ) { Integer a = 1;//装箱 Interger.valueof() Integer b = 2; System.out.println("Before swap:a="+a+",b="+b); //把 a,b 的值进行交换 swap(a,b); System.out.println("After swap:a="+a+",b="+b); } private static void swap( Integer a, Integer b ) { Integer tmp = a; a = b; b= tmp; }}
结果:
Before swap:a=1,b=2After swap:a=1,b=2
为什么没有改变呢?因为用的是值传递,图示如下:
1、初始状态
2.交换过后
所以swap方式只是改变了 num1和 num2的引用,并没有改变 a 和 b 的引用。
那么怎么实现 才是正确的呢?通过反射
private static void swap( Integer a, Integer b ) { try { Field field = Integer.class.getDeclaredField("value"); field.setAccessible(true); int tmp = a.intValue(); // 获取b的值,调用valueof field.set(a,b);//取b的值,走valueOf field.set(b,new Integer(tmp)); } catch (Exception e) { e.printStackTrace(); } }
总结
所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生,
会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断