In depth analysis of Java packing and dismantling

  • 2020-05-26 09:15:35
  • OfStack

Let's start with a piece of code:


public class Main{
  public static void main(String[] args){

    Integer num1 = 100;
    Integer num2 = 100;
    Integer num3 = 200;
    Integer num4 = 200;

    '''// The output '''
    System.out.println(num1==num2);
    System.out.println(num3==num4);
  }
}

Guess what?

A lot of people think it's all true, but it's not

true
false

Why is this the case? If the result is interpreted in memory, num1 and num2 point to the same object, while num3 and num4 do point to different objects. To tell you why, take a look at the source code of Integer type valueof method:


public static Integer valueOf(int i) {
  assert IntegerCache.high >= 127;
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + 128];
  return new Integer(i);
  }

Implementation of IntegerCache:


'''// IntegerCache . 1 Two inner classes, notice that its properties are all defined as static final'''
  private static class IntegerCache {
    static final int high; '''// Cache upper bound, temporarily null'''
    static final Integer cache[]; '''// Cached integer array '''

    '''//  A block. Why is it defined as a block '''
    static {
      final int low = -128; '''//  The cache bound is immutable. Only the upper bound can be changed '''

      '''// high value may be configured by property'''
      '''// h The value can be set jdk the AutoBoxCacheMax Parameter adjustment (explained below), automatic cache interval is set to [-128,N] . The lower bound of the interval is fixed '''
      int h = 127;

      if (integerCacheHighPropValue != null) {
        '''// Use Long.decode here to avoid invoking methods that'''
        '''// require Integer's autoboxing cache to be initialized'''
        //  Through the decoding integerCacheHighPropValue , and get 1 The upper bound of the candidate '''
        int i = Long.decode(integerCacheHighPropValue).intValue();
        '''//  I'm going to take the larger one as the upper bound, but it can't be greater than Integer The boundary of the MAX_VALUE'''
        i = Math.max(i, 127);   
        '''// Maximum array size is Integer.MAX_VALUE'''
        h = Math.min(i, Integer.MAX_VALUE - -low);
      }
      high = h; '''// To determine the upper bound '''
      '''//  You can create a cache block, notice the size of the cache array '''
      cache = new Integer[(high - low) + 1]; //
      int j = low;
      for(int k = 0; k < cache.length; k++)
        cache[k] = new Integer(j++); '''// -128 to high Value by 1 To the cache array '''
    }

    private IntegerCache() {}
  }

As can be seen from these two pieces of code, when creating an object of type Integer through the valueof method, the value range is [-128,127]. In this range, the pointer points to an existing object reference in IntegerCache.cache. When the value goes beyond this range, a new object will be created.

One thing to note is that not all types are in this range. Look at the Double type:


public class Main{
  public static void main(String[] args){

    Double i1 = 100.0;
    Double i2 = 100.0;
    Double i3 = 200.0;
    Double i4 = 200.0;

    System.out.println(i1==i2);
    System.out.println(i3==i4);
  }
}

Final output:

false
false

For details on why this is the case, you can look at the implementation of the Double valueof method in the source code, which differs from the Integer valueof method in that the number of integer values in a range is limited, while floating point Numbers are not.

Note that the implementation of the valueOf methods for the Integer, Short, Byte, Character, Long classes is similar.
The implementation of Double and Float's valueOf methods is similar.

One is pulled down, and the Boolean type results in two True or False. See the source code directly:


public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
  }

Where TRUE and FALSE are defined as follows:


public static final Boolean TRUE = new Boolean(true);

'''/** '''
'''* The <code>Boolean</code> object corresponding to the primitive '''
'''* value <code>false</code>. '''
'''*/'''
public static final Boolean FALSE = new Boolean(false);

Related articles: