Java如何处理原始数字和参考数字之间的长时间比较?

时间:2019-04-02 10:59:00

标签: java

我已经在笔记本电脑上尝试了以下源代码(Oracle HotSpot JVM,JDK 1.8、64位):

Long l;
Long l1 = 100L;
Long l2 = 100L;
System.out.println(Long.valueOf(100L) == Long.valueOf(100L));
System.out.println((l = 100L) == Long.valueOf(100L));
System.out.println(l1 == l2);
System.out.println(Long.valueOf(128L) == Long.valueOf(128L));
System.out.println(Long.valueOf(129L) == 129L);
System.out.println(Long.valueOf(255L) == new Long(255L));

然后我在 IntelliJ IDEA Community 2019.1 中反编译源代码以获取以下内容:

Long l1 = 100L;
Long l2 = 100L;
System.out.println(100L == 100L);
System.out.println(100L == 100L);
System.out.println(l1 == l2);
System.out.println(128L == 128L);
System.out.println(Long.valueOf(129L) == 129L);
System.out.println(255L == new Long(255L));

我有答案:

true
true
true
false
true
false

我已经知道从原始数字到相应参考数字的整数分配将被自动装箱。如果数字在[-128,127]中,则将使用缓存,这意味着第4、5、6、7、9行的结果是合理的。

但是,我很好奇Java如何处理第8行中参考数字和原始数字之间的比较?换句话说,原始数字实际上是如何存储在Oracle HotSpot JVM的内存中的?

到目前为止,我还没有找到任何帮助。任何建议将不胜感激。


已更新2019-04-02 19:25:24: 我试图显示Long.valueOf(129L)129L的地址,如下所示:

System.out.println(System.identityHashCode(Long.valueOf(129L)));
System.out.println(System.identityHashCode(129L));
System.out.println(System.identityHashCode(129L));

我得到以下信息:

731260860
1709366259
1335298403

它们显然是不同的对象,即使看起来它们是相同的原始数字129L

1 个答案:

答案 0 :(得分:2)

关于.class文件反编译的任何奇怪事情都可能不相关。它们可能只是意味着您使用的反编译器不可靠。因此,让我们忽略您的反编译代码。


测试基本类型和装箱的数值类型是否相等时的一般规则如下(简单版本):

  • <primitive-number> == <primitive-number>

    1. 如果值的类型不同,则将“较小”转换为较大的类型。
    2. 使用基本类型的顺序进行比较
  • <primitive-number> == <boxed-number><boxed-number> == <primitive-number>

    1. 将装箱的数字拆箱到对应的原始类型
    2. 如果值的类型不同,则将“较小”转换为较大的类型。
    3. 使用基本类型的顺序进行比较
  • <boxed-number> == <boxed-number>

    1. 如果装箱的类型不同:编译错误
    2. 如果装箱的类型相同,请根据引用的相等性进行比较。

JLS 11的相关部分是前两个项目符号为15.21.1,第三个项目符号为15.21.3。 (您应该发现从Java 5开始的所有JLS版本都说的基本上是一样的。)

一个复杂的问题是,将相同的原始值装箱两次可能会或可能不会为您提供相同的参考。它取决于类型和值,以及(在某些情况下)取决于JVM命令行开关(!)。

类型ByteShortIntegerLong都为其值空间的子范围维护盒装值的缓存。通常,该子范围是-128至+127(含),但这是未指定。如果在该范围内自动装箱原语,则将获得缓存的值。如果您使用<Type>.valueOf(<prim-type>)转换该范围 1 中的值,则同样适用。但是,如果您致电new <Type>(<prim-type>),则*总是会得到一个新创建的对象。

要解决的问题是,使用==比较两个带框的数字是一个坏主意,因为您得到的答案通常是无法预测的。


1-这是因为指定装箱以使用valueOf方法。