[Question Solving] Integer is assigned a constant 1 in auto-boxing, why does == determine true and false (JDK source code, internal buffer)

Table of Contents

answer:

1.low and high values in the if statement

2. What is returned in the if block

3.Outside the if statement block

Summarize

Question code

JDK source code related source code


The problem comes from the Integer exercise during the lecture

The first reaction at that time was false true true

There is no doubt that the output of the first paragraph is false, because two new heap spaces have been created, which of course point to different spaces.

But I have no clue about the second and third paragraphs. Doesn’t automatic boxing execute the same space?

In fact, it depends on the source code of the implicit call to Integer.valueOf during autoboxing.

Answer:

The output is false true true

The first paragraph is correct, but the second end implicitly calls the valueOf method of Integer. You can use debug to catch up.

1.low and high values in the if statement

After entering this method, you can see that there are if statements to judge and execute two returns. First, look at the if statements.

if (i >= IntegerCache.low & amp; & amp; i <= IntegerCache.high)

Who are IntegerCache.low and .high in this sentence? Then follow up and you will find

The low and high have been declared at the beginning of this class, and they are static. They have been assigned when the class is loaded, low=-128.

The important thing about this source code is to see whether the if statement is executed, and within this if statement block, what is executed is to determine whether the initial value is set during the virtual machine initialization. If the initial value is not set, it will default to empty because of the getSavedProperty method. Return java.lang.String is empty

String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

Call the virtual machine’s acquisition settings. If not entered during compilation, it will be empty.

public static java.lang.String getSavedProperty(java.lang.String s) { /* compiled code */ }

If it is empty, the if statement is not executed and high is given the default value 127, so min = -128, high = 127

2. What is returned in the if block

So far, we have solved the if judgment is from the value of -128 & & 127 (127 can be set through jvm)

Next, let’s discuss what the string after return is.

The first is cache. We can find that the format is an array. Using search, we can find an array of objects defined at the beginning.

Note that the object here is static, so it is created when the class is loaded. Let’s find where the static object is assigned or created.

Searching can be found that the cache array object creates an array with a size of 127 + 128 + 1 when the class is called. The value is assigned from j++ through the for loop, which is -128++ until 255. At this time, the k loop starts from 0 ~255, the value cycle is -128 to 127.

Then the if statement block is easy to understand. The cache is already a static object and has been created. You can directly return the array object subscript of the corresponding value. This mechanism is also called JDK’s internal buffer< /strong>

Outside the 3.if statement block

There is nothing to explain about this. If it is outside the range of -128 to 127, I will simply create a new object with the value of int i and return it to you.

For more analysis on the internal buffering of the JDK, please refer to

OpenJDK source code research notes (5) – caching frequently used data and objects such as Integer, greatly improving performance (a classic Java written test question)_51CTO blog_openjdk use

Summary

Because the value we assign in the second paragraph of the question is an int constant, we use automatic boxing to implicitly call the valueOf method. In this method, if is judged to be true, the static object cache[129] = Interger(1) is returned, so at this time The m points to the Interger(1) object, and similarly in the second sentence, n also points to the Interger(1) object, so sout(m == n) prints as true

Then in the third paragraph, the previous ones are the same, but x and y are not in -128~127, which is false when judging, and directly new a new space, so of course x and y execute two different new spaces, so == is false

So the correct answer is false true flase, done

Question Code

/**
 * @author Yinhai
 * @version 1.0
 */
public class WrapperExercise02 {
    public static void main(String[] args) {
        Integer i = new Integer(2);
        Integer j = new Integer(1);
        System.out.println(i == j); //False
        //So, here we mainly look at the range -128 ~ 127, which is to return directly
        /*
        Lao Han's interpretation
        //1. If i is in IntegerCache.low(-128)~IntegerCache.high(127), return it directly from the array
        //2. If it is not -128~127, just new Integer(i)
         public static Integer valueOf(int i) {
            if (i >= IntegerCache.low & amp; & amp; i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
         */
        Integer m = 1; //Underlying Integer.valueOf(1); -> Read the source code
        Integer n = 1;//Underlying Integer.valueOf(1);
        System.out.println(m == n); //T
        //So, here we mainly look at the range -128 ~ 127, which is to return directly
        //, otherwise, use new Integer(xx);
        Integer x = 128;//Underlying Integer.valueOf(1);
        Integer y = 128;//Underlying Integer.valueOf(1);
        System.out.println(x == y);//False

    }
}
 /**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage. The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch(NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k + + )
                cache[k] = new Integer(j + + );
    
    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value. If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since 1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low & amp; & amp; i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    /**
     * The value of the {@code Integer}.
     *
     * @serial
     */
    private final int value;

    /**
     * Constructs a newly allocated {@code Integer} object that
     * represents the specified {@code int} value.
     *
     * @param value the value to be represented by the
     * {@code Integer} object.
     */
    public Integer(int value) {
        this.value = value;
    }
}
syntaxbug.com © 2021 All Rights Reserved.