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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10149959/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 23:48:44  来源:igfitidea点击:

Using == operator in Java to compare wrapper objects

javaintegerwrapperequalsoperator-keyword

提问by dido

I'm reading SCJP Java 6 by Kathy Sierra and Bert Bates and this book is confusing me so much. On page 245 they state that the following code below.

我正在阅读 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

Then on the very next page they have the following code

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

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

//Prints output
same objects

I'm so confused! When I try this out on my own it seems that you cannot use the == to compare the same way you would use equals() method. Using the == always gives me 'false' even if the Integer variables are set to the same value (i.e. 10). Am I correct? Using the == to compare the same Integer object (with same values) will always result in 'false'

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

回答by dasblinkenlight

The key to the answer is called object interning. Java interns small numbers (less than 128), so all instances of Integer(n)with nin the interned range are the same. Numbers greater than or equal to 128 are not interned, hence Integer(1000)objects are not equal to each other.

答案的关键称为对象实习。Java 实习生人数较少(小于 128),因此实习范围内的所有Integer(n)with实例n都是相同的。大于或等于 128 的数字不会被保留,因此Integer(1000)对象彼此不相等。

回答by Steve Kuo

If you look at the source code for Integeryou'll see that Integer.valueOf(int)poolsall values -128 to 127. The reason is that small Integer values are used frequently and are thus worthy of being pooled/cached.

如果你看一下源代码,Integer你会看到Integer.valueOf(int)的所有值-128到127的原因是,小的整数值被频繁使用,因此,不愧是汇集/缓存。

Taken straight from Integer.java:

直接取自Integer.java

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

Note that this pooling is implementation specific and there's no guarantee of the pooled range.

请注意,此池化是特定于实现的,并且不能保证池化范围。

The answers about interning are correct in concept, but incorrect with terminology. Interning in Java normally implies that the Java runtime is performing the pooling (such as String's intern). In Integer's case it's the class itself that is doing the pooling. There's no JVM magic involved.

关于实习的答案在概念上是正确的,但在术语上是错误的。在 Java 中实习通常意味着 Java 运行时正在执行池化(例如 String 的实习生)。在 Integer 的情况下,是类本身在进行池化。不涉及 JVM 魔法。

回答by haskovec

The above answer about Interning is right on. Something to consider though if you do:

上面关于实习的答案是正确的。如果你这样做,需要考虑:

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

You will not have the new objects since you have created new objects explictly. If you write the code as follows it will be interned:

由于您显式地创建了新对象,因此您将不会拥有新对象。如果您按如下方式编写代码,它将被实习:

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

They will now be the same object again. If you take a look at the valueOf Method inside of the Integer.java class in the src.zip file you can see where it checks to see if the value of the int is outside of -128 to 127 it calls the new Integer class otherwise it loads it from the cache.

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

回答by josefx

Integer i1 = 1000;
Integer i2 = 1000;

The compiler 'boxes' the int 1000 as Integer object. To do this it converts the source to the following:

编译器将 int 1000 '装箱'为 Integer 对象。为此,它将源转换为以下内容:

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

Now valueOfcould be a simple call to new Integer(1000)however creating a new Integer object every time an intis boxed would cost both time and space. To avoid this the Integer class keeps an array of Integer objects for a limited range of int values.

现在valueOf可能是一个简单的调用,new Integer(1000)但是每次int被装箱时创建一个新的 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];
}

The speed gained vs. the memory lost to this can be adjusted by setting the range with a jvm argument at program start (afaik it defaults to -127 to 128).

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

回答by supercat

When the Java == operator is used to compare anything other than primitive types, it checks for referential equality; this applies even when the things being compared are wrapped primitives. Further, the valueOfmethod and compiler-generated autoboxing statement are generally free to arbitrarily return a new object which will not be reference-equal to any other previously-existing reference, or to return a reference to an existing object (which would, of course, be reference-equal to any pre-existing reference identifying the same object). Implementations are required to maintain a "pool" of Integerinstances for values -128 to 127, such that all calls to Integer.valueOfon any particular number within that range will return references to the same object, but other than that an implementation would be free to do something like

当 Java == 运算符用于比较原始类型以外的任何内容时,它会检查引用相等性;即使被比较的事物是包装的原语,这也适用。此外,该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;
}

I don't particularly expect Java implementations to do something like that, since in many cases the "cache hit" ratio could be near 0% and the extra time spent looking for instances in the cache would be wasted. Nonetheless, there is never any guarantee that a reference returned by instanceOfwon't match some previous reference returned by that method (even if it doesn't match the lastreference returned by that method, some caching algorithms might possibly cause it to return an earlierreference, especially if the pool is shared by multiple threads without locking. The lack of locking will never cause the code to return anything other than a reference to an integer with the correct value, but could cause unpredictable variations in which returned references compare equal). Only reference to Integerobjects created directly using the constructor new Integer(n)are guaranteed to be unique; code which expects any reference returned by valueOfto not match any reference returned by valueOf, without having actually observed that it does not match, should be considered broken.

我并不特别期望 Java 实现会做这样的事情,因为在许多情况下,“缓存命中”比率可能接近 0%,并且会浪费在缓存中查找实例所花费的额外时间。尽管如此,永远无法保证 返回的instanceOf引用与该方法返回的某些先前引用不匹配(即使它不匹配该方法返回的最后一个引用,某些缓存算法可能会导致它返回更早的引用)引用,特别是如果池由多个线程共享而没有锁定。缺少锁定永远不会导致代码返回对具有正确值的整数的引用以外的任何内容,但可能导致不可预测的变化,其中返回的引用比较相等)。只有对Integer直接使用构造函数创建的对象的引用才能new Integer(n)保证是唯一的;期望由 返回的valueOf任何引用与由 返回的任何引用不匹配的代码valueOf,而没有实际观察到它不匹配,应被视为已损坏。

回答by Antony Thomas Ramanattu

String comparison and integer comparison using == and != gives boolean results not as we expect.So be careful and make sure the possible unknown outcomes do not hinder the performance , reliability and accuracy of your software.

使用 == 和 != 的字符串比较和整数比较给出的布尔结果与我们预期的不同。所以要小心并确保可能的未知结果不会影响软件的性能、可靠性和准确性。

回答by vijay

"==" always compare the memory location or object references of the values. equals method always compare the values.but equals also indirectly uses the "==" operator to compare the values. Integer uses Integer cache to store the values from -128 to +127.If == operator is used to check for any values between -128 to 127 then it returns true. if any value between -128 to 127 as

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

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

other than the above range then it returns false

除了上述范围,则返回 false

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

Refer the linkfor some additional info

有关其他信息,请参阅链接

回答by Aniket Kulkarni

According to jls-5.1.7

根据jls-5.1.7

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f,   
or an int or short number between -128 and 127 (inclusive), then let r1 and r2 
be the results of any two boxing conversions of p. It is always the case that r1 == r2.

So, any number between -128and 127is cached by Interger class.
Remember, when comparing two objects always use equalsmethod.

因此,-128127之间的任何数字都由 Interger 类缓存。
请记住,比较两个对象时总是使用equals方法。

The caching code is written in IntegerCacheclass which is member of Integerclass.

缓存代码是在IntegerCache类中编写的,它是Integer类的成员。

Here is the code snippet:

这是代码片段:

 /**
 * 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=<size>} 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 property
        int 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_VALUE
                h = 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() {}
}

References

参考