27

为什么整数==运算符不适用于 128 和整数值之后?有人可以解释这种情况吗?

这是我的 Java 环境:

java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.12-b01, mixed mode)

示例代码:

Integer a;
Integer b;
a = 129;
b = 129;

for (int i = 0; i < 200; i++) {
    a = i;
    b = i;

    if (a != b) {
        System.out.println("Value:" + i + " - Different values");
    } else {
        System.out.println("Value:" + i + " - Same values");
    }
}

控制台输出的一部分:

Value:124 - Same values
Value:125 - Same values
Value:126 - Same values
Value:127 - Same values
Value:128 - Different values
Value:129 - Different values
Value:130 - Different values
Value:131 - Different values
Value:132 - Different values
4

7 回答 7

25

查看Integer 的源代码。您可以在那里看到值的缓存。

缓存仅在您使用时发生Integer.valueOf(int),而不是在您使用时发生new Integer(int)。您使用的自动装箱使用Integer.valueOf.

根据JLS,您始终可以依靠这样一个事实,即对于 -128 和 127 之间的值,在自动装箱后您会获得相同的 Integer 对象,并且在某些实现中,即使对于更高的值,您也可能会获得相同的对象。

实际上在 Java 7 中(我认为在 Java 6 的较新版本中),IntegerCache 类的实现发生了变化,上限不再是硬编码的,但它可以通过属性“java.lang.Integer.IntegerCache.高”,因此如果您使用 VM 参数运行程序-Djava.lang.Integer.IntegerCache.high=1000,您将获得所有值的“相同值”。

但是 JLS 仍然保证它只到 127:

理想情况下,对给定的原始值 p 进行装箱将始终产生相同的参考。在实践中,使用现有的实现技术这可能是不可行的。上述规则是一种务实的妥协。上面的最后一个条款要求某些常见的值总是被装箱到无法区分的对象中。实现可能会懒惰地或急切地缓存这些。

对于其他值,此公式不允许程序员对装箱值的身份进行任何假设。这将允许(但不要求)共享部分或全部这些引用。

这确保了在最常见的情况下,行为将是期望的行为,而不会造成过度的性能损失,尤其是在小型设备上。例如,内存限制较少的实现可能会缓存所有字符和短整数,以及 -32K - +32K 范围内的整数和长整数。

于 2013-02-22T13:07:11.823 回答
6

根据 Java 语言规范:

如果被装箱的值 p 是真、假、一个字节、一个 \u0000 到 \u007f 范围内的字符,或者一个介于 -128 和 127 之间的 int 或短数字,则令 r1 和 r2 为任意两次装箱转换的结果p。r1 == r2 总是如此。

JLS 拳击转换

有关 int 缓存的更多信息,请参阅本文

于 2013-02-22T13:05:53.643 回答
6

Integer是一个包装类int

Integer != Integer比较实际的对象引用,其中int != int将比较值。

如前所述,值 -128 到 127 被缓存,因此为这些值返回相同的对象。

如果超出该范围,将创建单独的对象,因此引用将不同。

要解决这个问题:

  • 制作类型int
  • 将类型转换为int
  • 采用.equals()
于 2013-02-22T13:08:14.427 回答
4

Integer 对象有一个内部缓存机制:

private static class IntegerCache {
    static final int high;
    static final Integer cache[];

    static {
        final int low = -128;

        // high value may be configured by property
        int h = 127;
        if (integerCacheHighPropValue != null) {
            // Use Long.decode here to avoid invoking methods that
            // require Integer's autoboxing cache to be initialized
            int i = Long.decode(integerCacheHighPropValue).intValue();
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - -low);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

    private IntegerCache() {}
}

另见 valueOf 方法:

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

这就是为什么你应该使用valueOf而不是new Integer. 自动装箱使用此缓存。

另见这篇文章:https ://effective-java.com/2010/01/java-performance-tuning-with-maximizing-integer-valueofint/

使用==不是一个好主意,使用等于来比较值。

于 2013-02-22T13:11:57.523 回答
2

使用.equals()而不是==.

整数值仅缓存 -127 到 128 之间的数字,因为它们最常使用。

if (a.equals(b)) { ... }
于 2013-02-22T13:06:42.927 回答
1

根据您获取Integer实例的方式,它可能不适用于任何价值:

System.out.println(new Integer(1) == new Integer(1));

印刷

false

这是因为==应用于引用类型操作数的运算符与这些操作数表示的值无关。

于 2013-02-22T13:15:48.480 回答
0

这是因为Integer类实现逻辑。它已经为数字准备了对象,直到 128。您可以查看 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Integer.java源代码-jdk 例如(搜索缓存[])。
基本上不应该使用对象来比较对象==,除了枚举之外的一个例外。

于 2013-02-22T13:12:27.943 回答