为什么通过引用比较整数 (==) 有效?

Why does comparing Integers by reference (==) work?

在 Herbert Schildt 的 "Java: The Complete Reference, 9th Edition" 中,有一个例子让我有些困惑。我无法理解的关键点可以概括为以下代码:

class Test {
    public static void main (String args[]) {               
        Integer i1 = 6;
        Integer i2 = 6;

        Integer i3 = 6;
        Integer i4 = (args.length + 1) * 6;

        if (i1 == i2) System.out.println("WTF");
        if (i3 == i4) System.out.println("Super WTF!!!");
    }
}

令我惊讶的是,使用JDK 8 update 40 编译执行该代码的结果如下:

WTF
Super WTF!!!

我看过的所有 Java 书籍、手册和其他信息资源都指出,相等运算符 (==) 在用于比较对象时,只是匹配它们的参考值。因此,如果两个对象变量引用不同的实例,则 == 运算符 returns false,即使这些对象的内部内容相同。这与上面示例所表达的行为完全不同。

在检查 SO 的类似问题时,我发现了一个 somewhat related one,它是关于使用 == 比较 String 个对象。那里提到了 Java 的一个有趣的特性,称为实习。显然,所有字符串文字和编译时字符串常量都是 JVM 的 "cached",因此,例如,使用相同字符串文字初始化的多个 String 引用实际上指向同一个对象。

但这里我们处理数值和 Integer 对象。此外,其中一个变量 i4 使用提供给程序的多个命令行参数进行初始化,这绝对是 运行 时间信息。然而,== 仍然发现它等于 i3

那么,考虑到以上所有内容,相等运算符究竟应该如何在 Java 中工作? 是否检查对象'比较时的内容?

谢谢!

我认为这个例子向我们展示了 java int 池是如何工作的。所以在 i4 的情况下,如果你在运行时没有提供参数,结果是 6。现在 int 池启动并使用 i1 值,它是 -128 的一部分到 127 int 池。因此,在对象级别上,它们实际上是相等的,这就是 == 的意义所在。

Integer 对象被缓存,如 Integer#valueOf(int) 的 Javadocs 所述:

This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

语句 Integer i4 = (args.length + 1) * 6; 调用 Integer#valueOf(int) return 缓存实例。另一方面,如果您使用 Integer i4 = new Integer((args.length + 1) * 6);,引用相等性将为 return false。

当您自动装箱一个 int 时,您在内部调用 Integer.valueOf(int),根据文档,它可能 return 缓存值。因此,您看到引用相等是完全合理的。

更一般地说,除非您显式构造它们,否则您永远不应假设两个引用是不同的。郑重声明,字符串驻留在运行时也可用,通过 String.intern() 方法。