面试题
说下面的整数类型之间比较的结果,以及原因
Integer i = new Integer(50); Integer j = new Integer(50); System.out.print(i == j); // ? Integer i = new Integer(50); Integer j = 50; System.out.print(i == j); // ? Integer i = 50; Integer j = 50; System.out.print(i == j); //? Integer i = 128; Integer j = 128; System.out.print(i == j); //? Integer i = new Integer(50); int j = 50; System.out.print(i == j); //? Integer i = 50; int j = 50; System.out.print(i == j); //?
大家都知道答案吗?
分析
主要考察你对基础知识的掌握,基本类型和包装类型,以及包装类型的缓存机制。
答案
最终输出的结果如下:
Integer i = new Integer(50); Integer j = new Integer(50); System.out.print(i == j); // false Integer i = new Integer(50); Integer j = 50; System.out.print(i == j); // false Integer i = 50; Integer j = 50; System.out.print(i == j); // true Integer i = 128; Integer j = 128; System.out.print(i == j); // false Integer i = new Integer(50); int j = 50; System.out.print(i == j); // true Integer i = 50; int j = 50; System.out.print(i == j); // true
首先我们区分下几个概念:
- Integer 是int的包装类, int是java中的基本类型,他们可以进行自动装箱、拆箱
- Integer的默认值是null, int的默认值是0
- Integer是一个对象,数据存储在堆山,变量存储着堆中的地址引用。int直接存储数据值,加载到栈上运算。
场景一: 两个new Integer()变量比较
结论: 两个new Integer()
变量比较,永远false
原因: 因为new Integer()
相当于在堆中开辟了一个新的空间,存放数据,内存地址必然不通,所以为false。
Integer i = new Integer(50); Integer j = new Integer(50); System.out.print(i == j); // false
场景二: Integer和new Integer()变量比较
结论:Integer
变量和new Integer()
变量比较,永远false
原因:new Integer()
指向的是堆中新建对象的地址, Integer x = 1中指向的可能堆中的地址也有可能是缓存中的数据,无论哪种情况,他们都是不一致的。
Integer i = new Integer(50); Integer j = 50; System.out.print(i == j); // false
场景三: 两个Integer变量比较
Integer i = 50; Integer j = 50; System.out.print(i == j); // true Integer i = 128; Integer j = 128; System.out.print(i == j); // false
结论: 两个Integer
变量比较,如果变量值在区间-128到127之间,则结果为true, 如果变量不在次范围内,结果为false。
原因:Integer i = 50
, 编译后会自动装箱变成 Integer i = Integer.valueOf(50)
, 然后我们看下valueOf的源码如下:
public static Integer valueOf(int i) { // 如果i大于等于IntegerCache中的-128,小于等于127,就会从缓存中获取, // 而缓存中的caches在初始化new出来 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; // 如果不在上面的区间内,则新建对象 return new Integer(i); }
根据源码得知,如果是在缓存范围内,会直接从缓存中获取,那么他们取到的是同一个对象,他们的地址也是一样的, == 为true, 否则为false。
场景四: 基本类型和Integer、new Integer()变量比较
Integer i = new Integer(50); //自动拆箱为 int i=100; 此时,相当于两个int的比较 int j = 50; System.out.print(i == j); // true Integer i = 50; int j = 50; System.out.print(i == j); // true
结论: 基本类型int和Integer、new Integer()变量比较时,只要两个值相等,则为true
原因: 包装类Integer遇到基本类型int时,自动会拆箱成int, 实际上就变成了两个int变量的比较。我们查看编译后的结果:i.intValue() == j
,通过调用intValue()
方法进行拆箱操作。
public int intValue() { return value; }
衍生扩展
因为 == 比较的不可靠,所以建议大家进行等值比较的时候用equals
, 上面无论哪种情况,用equals
准没错。
不仅int,Java中的另外7中基本类型都可以自动装箱和自动拆箱,其中也有用到缓存。见下表: