The difference between new Integer(112) and integer.valueof (112

The interviewer is trying to guess

There are many variations of this problem, and we’ll look at each of them.

Understand this problem, for the actual development process to prevent unexpected bugs are very useful, I suggest you seriously think and interpret.

Detailed background information

The implementation of Integer

Integer is a wrapper class for int, and its construction is implemented as follows.

    /**
     * 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;
    }
Copy the code

Integer defines a value property of type int. Since this property is of final type, it needs to be assigned via a constructor. The logic is very simple, not too much to focus on.

Conclusion: When an instance of an Integer is built using the new keyword, it allocates a chunk of heap memory address, as all normal object instantiations do.

Integer.valueOf

The integer. valueOf method, which converts a string to an Integer type, is defined as follows

public static Integer valueOf(String s) throws NumberFormatException {
  return Integer.valueOf(parseInt(s, 10));
}
Copy the code

This method calls another overloaded method, defined as follows.

public static Integer valueOf(int i) {
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
  return new Integer(i);
}
Copy the code

If the value of I is in the range integerCache. low and integerCache. high, the Integer object instance is returned using this code.

IntegerCache.cache[i+(-IntegerCache.low)];
Copy the code

Otherwise, use new Integer(I) to create a new instance object.

What is an IntegerCache?

From its name, it is not hard to guess that it should be cached. The simple guess is that if the value of I is in a certain range, the object is fetched directly from the cache.

The code for IntegerCache is defined as follows.

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

  static {
    // high value may be configured by property
    int h = 127; 
    // The value of high allows adjustment via system properties
    String integerCacheHighPropValue =
      sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    // If high is configured, the highest value of the two is taken as the highest range value of IntegerCache.
    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;
    // Create an array container
    cache = new Integer[(high - low) + 1];
    int j = low;
    // Iterate over initializes each object
    for(int k = 0; k < cache.length; k++)
      cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
  }

  private IntegerCache(a) {}}Copy the code

The implementation logic of the above code is very simple:

  1. The value range of IntegerCache is as follows:IntegerCache. Low = – 128, IntegerCache. Hign = 127, includinghignYes can be adjusted by system parameters.
  2. Create an Integer array and iterate over each value in the interval.

Why is Integer designed this way? A Cache is built to prevent the creation and destruction of objects in the range between -128 and 127. This means that any subsequent Integer instance that is not created with the new keyword will be retrieved from IntegerCache.

Problem solving

The difference between new Integer(112) and integer.valueof (112

It is easy to solve this problem once you understand the above principle.

  • New Integer creates an instance of an Integer object.

  • ValueOf (112). Integer provides the Cache mechanism by default. ValueOf does not create new object instances for data in the range -128 to 127.

The problem summary

Integer Specifies the number of morphing interview questions for this object, and one of them is typical.

There are two Integer variables a,b, swap a,b after the swap method, please write the swap method.

public class SwapExample {
 
    public static void main(String[] args){
        Integer a=1;
        Integer b=2;
        System.out.println("Before exchange: a="+a+",b="+b);
        swap(a,b);
        System.out.println("After exchange: a="+a+",b="+b);
    }
 
    private static void swap(Integer a,Integer b){
       //doSomething}}Copy the code

Students who are not very good at basics may be very straightforward to follow the “correct logic” to write the program, the possible code is as follows.

private static void swap(Integer a,Integer b){
  Integer temp=a;
  a=b;
  b=temp;
}
Copy the code

The program logic, which is fine in theory, is to define a temporary variable to store the value of A, and then swap between A and B. The actual results are as follows

Before switching: A =1,b=2 After switching: A =1,b=2Copy the code

Integer Specifies the reassignment of the object

Integer is the encapsulated object type. After passing the reference through the function, it is theoretically true that a and B defined in main and a, b, and B passed in swap refer to the same memory address.

There are two types of parameter passing in Java.

  • Value passing, in which a copy of the data is passed, changes in formal parameter values during method execution do not affect the actual parameter values.
  • Reference passing is passing a reference to a memory address. In the execution of a method, since the address of the referenced object points to the same block of memory, the modification of the object data will affect the variable that references the address.

The advantage of this design is to reduce memory usage and improve access efficiency and performance.

So why does Integer, as an encapsulation type, pass a copy instead of a reference?

If we look at the value value definition in Integer, we can see that the property is final, meaning it cannot be changed.

    /**
     * The value of the {@code Integer}.
     *
     * @serial* /
    private final int value;
Copy the code

Conclusion: In Java, there is only one way to pass parameters, and that is by value. However, when a parameter is passed as a basic type, a copy of the value is passed. The modification of the copied variable does not affect the original variable. When a reference type is passed, a copy of the reference address is passed, but the copied address and the real address refer to the same real data, so the value in the original variable can be modified. When an Integer is passed, the reference address is copied to the same data, but the value of the Integer cannot be changed, so the value in the original variable cannot be changed.

Therefore, the code above failed to swap because a and B passed to swap create a copy of the variable whose values are swapped without affecting the original values.

With this knowledge in mind, the problem becomes how to make data changes to a property that modifies the final keyword. That’s done by reflection, and the code is as follows.

public class SwapExample  {

    public static void main(String[] args){
        Integer a=1;
        Integer b=2;
        System.out.println("Before exchange: a="+a+",b="+b);
        swap(a,b);
        System.out.println("After exchange: a="+a+",b="+b);
    }

    private static void swap(Integer a,Integer b){
        try {
            Field field=Integer.class.getDeclaredField("value");
            Integer temp= a;
            field.setAccessible(true); // This method is used to set variables that are private.
            field.set(a,b);
            field.set(b,temp);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch(IllegalAccessException e) { e.printStackTrace(); }}}Copy the code

Does this code run as expected? The results of the above program are as follows:

Before switching: A =1,b=2 After switching: A =2,b=2Copy the code

It turns out that there was a change, but it wasn’t complete, because the expected value of b=1 didn’t happen. Why is that? Actually, it’s related to the topic we share today, so let’s take a look at it step by step.

  1. Integer temp=aThis place, based on IntegerCache, does not generate a new instance of Temp, meaning that the temp variable andaThe variable points to the same memory address.
  2. When usingfield.setThe method,aThe value of the memory address is modified by reflectionbLater, then at this pointaThe value of theta should be theta2. Note: since the value of the memory address changed to 2, whiletempThis variable again refers to that memory address, sotempThe value of theta naturally becomes 2.
  3. Then use thefiled.set(b,temp)Modify thebProperty at this timetempIs 2, so the result is obtainedbIt also becomes 2.
private static void swap(Integer a,Integer b){
  try {
    Field field=Integer.class.getDeclaredField("value");
    Integer temp= a;  
    field.setAccessible(true); // This method is used to set variables that are private.
    field.set(a,b);
    field.set(b,temp);
  } catch (NoSuchFieldException e) {
    e.printStackTrace();
  } catch(IllegalAccessException e) { e.printStackTrace(); }}Copy the code

Now that we understand how this works, all we need to do is change the Integer temp=a code to something like this. Ensure that the temp variable is a separate instance.

Integer temp=new Integer(a);
Copy the code

The result is as follows

Before the exchange: a=1,b=2After the exchange: A =2,b=1
Copy the code

Mic says: Only with solid basic skills can you see through the nature of any problem at a glance and solve it with ease.