为什么通过引用比较整数 (==) 有效?
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()
方法。
在 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()
方法。