java Interger包装类不能使用“==“判断值相等
今天看到朋友发的一个 面试题

我将代码拷贝到编译器后第一反应是idea提醒不能使用 "= =“去判断并且提示将”=="置换为equal()方法。

看到这个想起来自己背的内容
“如果是基本类型判断两个变量的值是否相等用‘= =’和equal()得到的结果相同;
如果变量是引用类型,‘==’ 判断变量是否指向同一引用对象,equal()判断变量 ‘值’ 是否相等”。
Interger是引用类,所以当我们使用’=='去判断i1与i2,i4与i5是否相等的时候实际上判断的是是否为同一引用对象即内存中指向的地址是否相同。
判断之前我们先看一下上面判断打印的结果:

小菜鸡一时陷入迷茫,当我点进去看了Interger.valueOf()源码后找到了原因。
/*** Returns an {@code Integer} instance representing the specified* {@code int} value. If a new {@code Integer} instance is not* required, this method should generally be used in preference to* the constructor {@link #Integer(int)}, as this method is likely* to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since 1.5*/public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
继续深入IntergerCache是什么
/*** Cache to support the object identity semantics of autoboxing for values between* -128 and 127 (inclusive) as required by JLS.** The cache is initialized on first usage. The size of the cache* may be controlled by the {@code -XX:AutoBoxCacheMax=} option.* During VM initialization, java.lang.Integer.IntegerCache.high property* may be set and saved in the private system properties in the* sun.misc.VM class.*/ private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint 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_VALUEh = 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() {}}
看了这两段源码后想必大家也都明白了其中的道道,当传入的参数"i"大于等于 IntegerCache.low 且小于等于IntegerCache.high 的时候返回 IntegerCache.cache[i + (-IntegerCache.low)],否则 new 一个Integer变量返回,顾名思义IntegerCache 就是Integer的缓存用的相关静态类, 在Integer里定义了一个私有的静态内部类 IntegerCache ,在其中定义了 静态Integer数组 cache ,长度为 high = 127 和 low = -128 之间的差值,并且存储的是 从 low到high,即-128到127的值。
感悟:
1.如果定义的变量在 -128到127之间,则是直接去缓存cache里的值,所以如果数值一致则对应的地址值也会一致,所以我们用 == 判断两个值是否相等,是返回 true的;
2.如果定义的变量不在 -128到127之间,则通过new Integer(int i)的方式创建数值,并且每次都会重新new一个对象,这就导致每次的对象的数值即使一样但是地址值不一致,所以此时用 == 判断两个值是否相等就不如我们所愿了;
3.所以我们遇到包装类 Integer定义的变量的时候,如果要判断两个变量的值是否相等,则使用 equals来判断,尽量不要用 == 的来判断。
既然都提到这了顺带提一嘴Interger类型与int比较;
1 int与Integer的基本使用对比
(1)Integer是int的包装类;int是基本数据类型;
(2)Integer变量必须实例化后才能使用;int变量不需要;
(3)Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值 ;
(4)Integer的默认值是null;int的默认值是0。
2 int与Integer的深入对比
(1)由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false
(2)Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true
(3)非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
(4)对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //trueInteger i = 128;
Integer j = 128;
System.out.print(i == j); //false
下面举个栗子咯

public static void main(String[] args) {Integer a = 1 ;Integer b = 2 ;Integer c = 3 ;Integer d = 3 ;Integer e = 321 ;Integer f = 321 ;Long g = 3L;Long h = 2L;System.out.println(c == d);System.out.println(e == f);System.out.println(c == (a + b));System.out.println(c.equals((a+b)));System.out.println(g == (a+b));System.out.println(g.equals(a+b));System.out.println(g.equals(a+h));}
输出结果:
true
false
true
true
true
false
true
分析:第一个和第二个结果没什么疑问,Integer类在-128到127的缓存问题;
第三个由于 a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),==比较符又将左边的自动拆箱,因此它们比较的是数值是否相等。
第四个对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。
第五个对于 g == (a+b),首先计算 a+b,也是先调用各自的intValue方法,得到数值之后,由于前面的g是Long类型的,也会自动拆箱为long,==运算符能将隐含的将小范围的数据类型转换为大范围的数据类型,也就是int会被转换成long类型,两个long类型的数值进行比较。
第六个对于 g.equals(a+b),同理a+b会先自动拆箱,然后将结果自动装箱,需要说明的是 equals 运算符不会进行类型转换。所以是Long.equals(Integer),结果当然是false
第七个对于g.equals(a+h),运算符+会进行类型转换,a+h各自拆箱之后是int+long,结果是long,然后long进行自动装箱为Long,两个Long进行equals判断。
参考链接:https://blog.csdn.net/i6223671/article/details/88873163
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
