[Java]_ [primary]_ [traps for packing and unpacking - do not use = = for package type wrapper class comparison]

Keywords: Java wrapper

scene

  1. When using Java Integer for arithmetic operation, it is occasionally found that the result is false under the premise that the two int values of = = comparison operator are the same. What is the reason?

explain

  1. JDK5 has started to provide auto boxing and auto unboxing functions. The purpose is to facilitate the conversion between original data types and wrapper types, as well as arithmetic operations. In this way, it does not need to call Integer.intValue() or Integer.valueOf() frequently to convert types

  2. Another function is that in the collection class, the generic type must be a reference type. Therefore, there is no such writing method as list < int > and can only be list < Integer > or list < Object >. Some methods that require object as a parameter will be automatically converted to Integer when passing int type, which is more convenient

  3. When Integer is used for arithmetic and comparison operations, it will automatically unpack for int type calculation. However, there is a = = comparison operator supported by all objects. If Integer == Integer comparison is performed, Object.equals is actually called for comparison, not arithmetic comparison. Pay attention to this. Again, don't perform = = comparison on two types of integers. Convert one Integer to int and then compare two = = comparisons. Other comparison operators, such as > = will be unpacked for int comparison, which is correct

It is possible to compare the following two Integer types = = with each other

print("ie4 == ie5",ie4.compareTo(ie5) == 0);
print("ie4.intValue() == ie5",ie4.intValue() == ie5);
print("ie4+0 == ie5", (ie4+0) == ie5);
print("(int)ie4 == ie5", (int)ie4 == ie5); 
  1. As for the static buffer used if the Integer value is in the [- 128127] interval [2], a = = comparison can also be performed. But it's useless. Since you don't know its specific value for comparison, you don't need to consider this comparison. You'd better manually convert it to int for = = comparison

valueOf implementation by JDK:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  1. In addition to Integer type, the following package types support the corresponding original type:
Primitive typeWrapper class
booleanBoolean
byteByte
charCharacter
floatFloat
intInteger
longLong
shortShort
doubleDouble

example

  1. The following are various cases where Integer and int are boxed:

AutoBoxingTest

package com.example.string;

import org.junit.jupiter.api.Test;



public class AutoBoxingTest {
    
    public static<T> void print(String key,T t){
        System.out.println(key +" : "+t);
    }

    
    public static<T> void add_1(Integer input){
        input += 1;
    }

    public static void add_2(int input){
        print("add_2",input); // Calling a generic method automatically boxing to Integer type
    }

    @Test
    public void testInteger(){

        //Case 1. Integer can be used for arithmetic operators. When encountering arithmetic operators, it is automatically unpacked as int type
        Integer ie1 = Integer.valueOf(10); // Creates an immutable Integer object
        print("ie1",ie1); // 10
        print("ie1 id",System.identityHashCode(ie1));
        ie1 += 100; 
        ie1 = ie1 +10;
        print("ie1",ie1); // 120
        print("ie1 id",System.identityHashCode(ie1)); // Note: the object ID has changed and ie1 points to a different Integer object


        //Case 2: Integer is passed as a parameter value
        int i1 = ie1; // It can be assigned to the original variable and unpacked automatically
        print("i1",i1); // The 120 value did not change 
        add_1(ie1); // Parameters that can be passed to the original variable 
        print("ie1",ie1); // The 120 value did not change

        // Case 3: Integer can be passed to the method of int parameter.
        add_2(ie1); // 120

        // Case 4: automatic boxing when int is passed to Integer parameter method
        add_1(i1);
        print("ie1",ie1); // 120
        
        // Case 5: automatic boxing when int is assigned to Integer variable
        Integer ie2 = new Integer(120);
        print("ie2",ie2); // 120
        Integer ie3 = 120;
        print("ie3",ie3); // 120
        
        //  Case 6: comparison operators between Integer and int are not allowed
        print("ie2 > ie1",(ie2 >= ie1)); //true
        print("ie2 == ie1",(ie2 == ie1)); // false
        print("ie3 == ie1",(ie3 == ie1)); // True - 128 < = ie < = 127 uses constant pool objects, so the comparison is the same
            
        Integer ie4 = 290;
        Integer ie5 = 290;    
        print("ie4 == ie5",(ie4 == ie5));  // False > 127, a new object is created.  
        print("ie4 >= ie5",(ie4 >= ie5)); // true auto unpacking is int comparison
        // Use compareTo to determine equality
        print("ie4 == ie5",ie4.compareTo(ie5) == 0); // true
        // In conclusion, do not use the = = symbol to compare two Integer type data
        // When integer and int operate, integer will automatically unpack to type int, and the result will also be type int. after comparing int with integer, integer will automatically unpack
        print("ie4+0 == ie5", (ie4+0) == ie5); // true
        print("(int)ie4 == ie5", (int)ie4 == ie5); // The true int cast is the same as the assignment of integer to int, which will unpack
        print("ie4.intValue() == ie5",ie4.intValue() == ie5); // true
        
        // The comparator used for non wrap types can only be = =    
        String s1 = "1"; // Constant Storage 
        String s2 = new String("1"); // Non constant pool
        //If (S1 > S1) / / if the non Wrapper type is compiled with the non = = comparison operator, an error is reported
        print("s1 == s2",(s1 == s2));  //false is converted to using equals() for comparison, so it is different
            
        // List<int> tt; //  Compilation error
    }
    
}

output

reference resources

  1. Autoboxing and Unboxing

  2. Why is 128128 false but 127127 is true when comparing Integer wrappers in Java?

  3. Java boxing and unpacking 128 trap problems

Posted by chronister on Tue, 14 Sep 2021 19:22:56 -0700