I've tried the following source code on my laptop (Oracle HotSpot JVM, JDK 1.8, 64 bits):
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));
Then I decompiled the source code in IntelliJ IDEA Community 2019.1 to get following content:
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));
And I've got answers:
true
true
true
false
true
false
I already know that integer assignment from a primitive number to the corresponding reference number will be automatically boxed. And the cache will be used if the number is in [-128,127], which means the results of lines 4, 5, 6, 7, 9 are reasonable.
However, I'm very curious about how Java handles the comparison between a reference number and a primitive number on line 8? In other words, how are primitive numbers actually stored in memory in Oracle HotSpot JVM?
I haven't found any help so far. Any suggestion will be appreciated.
Updated 2019-04-02 19:25:24:
I've tried to show the addresses of Long.valueOf(129L)
and 129L
as follows:
System.out.println(System.identityHashCode(Long.valueOf(129L)));
System.out.println(System.identityHashCode(129L));
System.out.println(System.identityHashCode(129L));
I got the following information:
731260860
1709366259
1335298403
They are obviously different objects, even if it seems like they are the same primitive number, 129L
.
Any strange things about the decompilation of the .class file are probably not relevant. They could simply mean that the decompiler that you used is unreliable. So lets ignore your decompiled code.
The general rules when testing equality of primitive and boxed numeric types are as follows (simple version):
<primitive-number> == <primitive-number>
:
<primitive-number> == <boxed-number>
or <boxed-number> == <primitive-number>
:
<boxed-number> == <boxed-number>
The relevant sections of the JLS 11 are 15.21.1 for the first two bullets and 15.21.3 for the third one. (You should find that all editions of the JLS from Java 5 onward say essentially the same thing.)
The complicating issue is that boxing the same primitive value twice may or may not give you the same reference. It depends on the type and the value and (in some circumstances) on JVM command line switches(!).
The types Byte
, Short
, Integer
and Long
all maintain a cache of boxed values for a subrange of their value space. Typically the subrange is from -128 to +127 inclusive, but this is not specified. If you autobox a primitive in that range, you will get the cached value. The same applies if you used <Type>.valueOf(<prim-type>)
to convert a value in that range1. But if you call new <Type>(<prim-type>)
you will *always get a newly created object.
The take away is that it is a bad idea to use ==
to compare two boxed numbers because the answer you get is often unpredictable.
1 - This is because boxing is specified to use the valueOf
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With