英文原文:
https://dzone.com/articles/why-1000-1000-returns-false-but-100-100-returns-tr
Java.jpg
这是一个非常有意思并且值得讨论的话题。
如果你运行下面的代码:
Integer a = 1000, b = 1000;
System.out.println(a == b);//1
Integer c = 100, d = 100;
System.out.println(c == d);//2
你将得到这样的结果:
fasle
true
先了解一下基础知识:我们知道,如果两个引用指向相同的对象,它们在 ==
表达式中是相等的;如果两个引用指向不同的对象,尽管它们拥有相同的内容即值,在 ==
表达式中也是不相等的。
所以,按道理,上面第二条语句也应该返回 false 。
这就是它有意思的地方了。如果你去翻阅 Java 源代码,查看 Integer.java
类的话,你会发现在这个类里面有一个内部私有类 —— IntegerCache.java
,这个内部私有类缓存了数值为 -128 到 127 之间所有的整型对象。
那么原理就搞清楚了,所有的小整数都被缓存到内部,然后当我们类似这样定义的时候 ——
Integer c = 100;
它在内部做了如下处理:
Integer i = Integer.valueOf(100);
如果我们继续翻阅 valueOf()
的源代码,将会看到 ——
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}
如果数值处于 -128 到 127 之间,它将返回缓存中的实例。
所以…
Integer c = 100, d = 100;
从根本上来讲,指向了相同的对象。
这就是为什么如果我们这样写:
System.out.println(c == d);
将得到 true 。
现在也许你会问,为什么这里需要缓存?
从逻辑基础上来讲,处于这个范围的小整数比大整数要使用的多,所以,对于减少潜在的内存占用,使用相同的底层对象更有价值。
然而,通过使用反射API,你可能会滥用这个功能。
运行下面一段代码,并且享受它的魅力吧
public static void main(String[] args) throws public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class cache = Integer.class.getDeclaredClasses()[0]; //1
Field myCache = cache.getDeclaredField("cache"); //2
myCache.setAccessible(true);//3
Integer[] newCache = (Integer[]) myCache.get(cache); //4
newCache[132] = newCache[133]; //5
int a = 2;
int b = a + a;
System.out.printf("%d + %d = %d", a, a, b); //
}