在Java中使用==运算符来比较包装器对象

我正在读Kathy Sierra和Bert Bates的SCJP Java 6,这本书让我非常困惑。 在页面245他们声明下面的代码。

Integer i1 = 1000; Integer i2 = 1000; if(i1 != i2) System.out.println("different objects"); //Prints output different objects 

然后在下一页他们有以下代码

 Integer i3 = 10; Integer i4 = 10; if(i3 == i4) System.out.println("same objects"); //Prints output same objects 

我很困惑! 当我自己尝试这个,似乎你不能使用==比较相同的方式,你会使用equals()方法。 即使整数variables设置为相同的值(即10),使用==总是给我“假”。 我对么? 使用==比较相同的Integer对象(具有相同的值)将始终导致“false”

答案的关键是被称为对象实习 。 Java实现了小数字(小于128),因此在interned范围内的所有Integer(n)n实例都是相同的。 大于或等于128的数字不被限制,因此Integer(1000)对象不相等。

如果你看一下Integer的源代码,你会看到Integer.valueOf(int)所有的值合并为-128到127.原因是小的Integer值经常被使用,因此值得被合并/caching。

直接从Integer.java取出:

 public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); } 

请注意,该池是特定于实现的,并不保证池范围。

关于实习的答案在概念上是正确的,但是在术语上是不正确的。 在Java中实施通常意味着Java运行时正在执行池(如String的实习生)。 在Integer的案例中,这个课程本身就是在进行共享。 没有涉及JVM的魔法。

以上关于Interning的回答是正确的。 有些事情要考虑,但如果你这样做:

 Integer i3 = new Integer(10); Integer i4 = new Integer(10); 

你将不会有新的对象,因为你明确地创build了新的对象。 如果您按照以下方式编写代码,将会被禁用:

 Integer i3 = Integer.valueOf(10); Integer i4 = Integer.valueOf(10); 

他们现在会再次成为同一个对象。 如果你看一下src.zip文件中Integer.java类的valueOf方法,你可以看到它的检查位置是否在-128到127之外,否则调用新的Integer类它从caching中加载它。

 Integer i1 = 1000; Integer i2 = 1000; 

编译器将int 1000作为Integer对象“框”。 要做到这一点,它将源代码转换为以下内容:

 Integer i1 = Integer.valueOf(1000); Integer i2 = Integer.valueOf(1000); 

现在valueOf可以是一个简单的调用new Integer(1000)但是每次int被装箱时都会创build一个新的Integer对象会花费时间和空间。 为了避免这种情况,Integer类为int值的有限范围内保存了一个Integer对象的数组。

 if(value> maxRange || value< minRange){ //not in pool return new Integer return new Integer(value); }else{ //return pooled Integer object //for the value, pool contains all Integer //values from minRange to maxRange return integerPool[value-minRange]; } 

与失去的内存相比,获得的速度可以通过在程序启动时使用jvm参数设置范围来调整(afaik默认为-127到128)。

当使用Java ==操作符比较基本types以外的任何东西时,它会检查引用是否相等; 即使在被比较的东西是包装原语时也是如此。 此外, valueOf方法和编译器生成的自动装箱语句通常可以自由地任意返回一个新的对象,该对象不会被引用等于任何其他先前存在的引用,或者返回一个对现有对象的引用(当然,引用等于任何标识相同对象的预先存在的引用)。 需要实现来维护Integer实例的“池”,值为-128到127,这样,对该范围内的任何特定数字的Integer.valueOf所有调用将返回对同一对象的引用,但除了实现将是自由地做类似的事情

 static Integer [] intPool = new Integer[256]; public Integer valueOf(int n) { int hash = (n*0x18675309) >>> 24; Integer instance = intPool[n]; if (instance == null && instance.value != n) { instance = new Integer(n); intPool[hash] = instance ; } return instance; } 

我并不特别期望Java实现这样做,因为在许多情况下,“caching命中率”可能接近0%,在caching中查找实例花费的额外时间将被浪费。 尽pipe如此,从来没有保证instanceOf返回的instanceOf不匹配该方法返回的前一个引用(即使它与该方法返回的最后一个引用不匹配,某些cachingalgorithm可能会导致它返回特别是如果这个池被多个线程共享而没有locking的话,那么缺lesslocking将永远不会导致代码返回除正确值的整数之外的任何东西,但是会导致不可预知的变化,其中返回的引用比较相等)。 只有对使用构造函数new Integer(n)直接创build的Integer对象的引用才能保证是唯一的; 如果代码中valueOf返回的任何引用与valueOf返回的引用不匹配,而实际上没有发现它不匹配,则应该被视为中断。

使用==和!=进行string比较和整数比较的结果并不像我们预期的那样。所以要小心并确保可能的未知结果不会妨碍软件的性能,可靠性和准确性。

“==”总是比较值的内存位置或对象引用。 equals方法总是比较值,但也等于间接使用“==”运算符来比较值。 Integer使用Integercaching来存储从-128到+ 127的值。如果==运算符用于检查-128到127之间的任何值,则返回true。 如果-128到127之间有任何值

 Integer i1 = -128; Integer i2 = -128; System.out.println(i1 == i2); // returns true 

除了上面的范围,那么它返回false

 Integer i1 = 1000; Integer i2 = 1000; System.out.println(i1 == i2); // returns false 

请参阅链接了解更多信息