Does == use byte comparison in an ArrayList comparison?

In the program I was working on, I ran into a data storage problem, especially related to ArrayLists. This is not the code I tested, but it gives an example of what I mean.

public class test { public static void test() { ArrayList<Integer> bob = new ArrayList<Integer>(); bob.add(129); bob.add(129); System.out.println(bob.get(0) == 129 ); System.out.println(bob.get(1) == 129 ); System.out.println(bob.get(0) == bob.get(1) ); } } 

If you run it, you will get true, true and false. The code recognizes that both values ​​are 129, but for some reason returns false when it tries to see if they are equal to each other. However, if you change the value to 127, it will return true, true, and true. Repeating this several times for different values, you will see that the minimum value to get true, true and true is -128, and the maximum value is 127. This is an interval for a byte, which makes me suspect that the == operation is using a byte in this case .

Interestingly, if you change the code so that it reads

 public class test { public static void test() { ArrayList<Integer> bob = new ArrayList<Integer>(); bob.add(129); bob.add(129); int a = bob.get(0); int b = bob.get(1); System.out.println(a == 129 ); System.out.println(b == 129 ); System.out.println(a == b ); } } 

it works as intended. true, true and true. Why does saving values ​​as int before comparing change the result? This is because if they are not saved, the comparison will use the default bytes for comparison ==

+6
source share
6 answers

The answer lies in the caching mechanism of the primitive wrapper classes that Java uses.
In the case of integers, caching is performed for values ​​from -128 to 127 (i.e., a range of byte values).

This means that if you set any value from -128 to 127, you will get a ready-made instance from the cache. This is why the == operator works for them, as it compares links, not values.
On the other hand, if you use any other value, you will get a new new instance for each box, which means that the == operator will fail.

Here is the code snippet from the Integer class that is responsible for this:

 private static class IntegerCache { private IntegerCache(){} static final Integer cache[] = new Integer[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); } } 
+3
source

That's right, I just realized that I can explain this. I don’t know what I was thinking before.

JLS Section 5.1.7:

If the value of p placed in the square is an integer literal of type int between -128 and 127 inclusive (§3.10.1) or a logical literal true or false (§3.10.3) or a character literal between '\ u0000' and '\ u007f' inclusive (§3.10.4), then let a and b be the results of any two box transformations p. It always happens that a == b.

Since 129 is outside this range, you will get two different Integer objects at indices 1 and 2, unless you yourself configure the range using the JVM flags.

For the last comparison in the first bit of code: As ArrayList#get() returns an object of the type with which ArrayList parameterized, the last comparison compares two Integer objects, and since both objects are different, the result will be false . The first two comparisons cause the Integer objects to be unpacked because you are comparing the Integer wrapper with an int literal, so the results look exactly as you would expect.

The second bit of code works as you expect, because you are comparing int literals, and these comparisons are more intuitive.

+2
source

This is because the third test compares two objects, because the return () of get() calls is not decompressed. Values ​​for which the result is true are cached singletones and, therefore, the same object, but outside this range, new and separate objects are put into the list by automatic boxing.

Note that this behavior can vary from JVM to JVM and version to version; on some JVMs it can even be dynamic, based on some heuristic - for example, the system could, apparently, look at available memory and cache 16-bit values ​​instead of 8.

+1
source

Autoboxing and unboxing work, it works -

 bob.add(129); // Autoboxed to Integer int a = bob.get(0); // primitive int a int b = bob.get(1); // primitive int b System.out.println(a == 129 ); // primitive to primitive System.out.println(b == 129 ); // primitive to primitive System.out.println(a == b ); // primitive to primitive 

You can also use Integer.intValue () ,

 Integer a = bob.get(0); Integer b = bob.get(1); // Here you could omit one, but not both, calls to intValue() System.out.println(a.intValue() == b.intValue()); // primitive to primitive 
+1
source

This is because the first two comparisons relate to int values, because bob.get() gets cast to int before the comparison. in the third case, the comparison is performed on objects, and for this reason you get a false value outside the -128 to 127 values, because in this range the values ​​are cached.

Hope this helps.

+1
source

Collections have 2 retrieval methods that accept int and Integer with entire collections, autoboxing does the inner magic to use the wrong method (Effective Java)

Use an explicit box or unzip if necessary.

+1
source

Source: https://habr.com/ru/post/970019/


All Articles