Java中有两种类型
- 基本类型
基本数据类类型存的是数值本身
- 引用类型
引用类型变量在内存放的是数据的引用
基本类型通过==比较的是他们的值大小,而引用类型比较的是他们的引用地址
如果你运行下面的代码
1
2
3
4
|
Integer a =
1000
, b =
1000
;
System.out.println(a == b);
//1
Integer c =
100
, d =
100
;
System.out.println(c == d);
//2
|
你会得到
1
2
|
false
true
|
基本知识:我们知道,如果两个引用指向同一个对象,用==表示它们是相等的。如果两个引用指向不同的对象,用==表示它们是不相等的,即使它们的内容相同。
因此,后面一条语句也应该是false 。
这就是它有趣的地方了。如果你看去看 Integer.java 类,你会发现有一个内部私有类,IntegerCache.java,它缓存了从-128到127之间的所有的整数对象。
所以事情就成了,所有的小整数在内部缓存,然后当我们声明类似——
1
|
Integer c =
100
;
|
的时候,它实际上在内部做的是
1
|
Integer i = Integer.valueOf(
100
);
|
现在,如果我们去看valueOf()方法,我们可以看到
1
2
3
4
5
|
public
static
Integer valueOf(
int
i) {
if
(i >= IntegerCache.low && i
return
IntegerCache.cache[i + (-IntegerCache.low)];
return
new
Integer(i);
}
|
如果值的范围在-128到127之间,它就从高速缓存返回实例。
所以…
1
|
Integer c =
100
, d =
100
;
|
指向了同一个对象。
这就是为什么我们写
1
|
System.out.println(c == d);
|
我们可以得到true。
现在你可能会问,为什么这里需要缓存?
合乎逻辑的理由是,在此范围内的“小”整数使用率比大整数要高,因此,使用相同的底层对象是有价值的,可以减少潜在的内存占用。
然而,通过反射API你会误用此功能。
代码片段
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
a == b分析
Integer b = 3; 自动调用Integer.valueOf(3) 返回一个Integer的对象。 这个对象存放到cache中的(上面一段代码分析)。 而 Integer a = new Integer(3);这里创建了一个新的对象Integer 所以 a == b 返回的是false
a == c 分析
一个Integer 与 int比较,先将Integer转换成int类型,再做值比较,所以返回的是true。
参考资料:《探索java基本类型和包装类型的使用运算符==进行比较的底层细节》
延伸
java中还有与Integer类似的是Long,它也有一个缓存,在区间[-128,127]范围内获取缓存的值,而Long与long比较的时候先转换成long类型再做值的比较
Double类型,它没有缓存,但是当Double与double比较的时候会先转换成double类型,再做值的比较
一道牛客网的习题
分析:
A: Integer 与 int 比较的时候将Integer转成int在比价两个值大小,所以排除
B: Integer i01 = 59;默认处理Integer i01 =Integer.valueOf(59); i01与 i03数值在-128 - 127之间,所以在cache缓存中获取Integer对象,他们引用地址是一样的。所以排除
C: i03获取的是cache中缓存好的的Integer地址,而i04是重新在堆中创建一个地址,所以两个地址是不一样的
D:A一样的原理。