Interview question: the difference between new Integer(112) and Integer.valueOf(112)
Interviewer survey point conjecture #
This question examines the understanding of the object principle of Integer. There are many variants of this question, which we will analyze one by one.
Understanding this problem is very useful for preventing unexpected bugs in the actual development process. It is recommended that you think and interpret it carefully.
Detailed background knowledge #
Implementation of Integer #
Integer is an encapsulated class of int. its construction and implementation are 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; }
Integer defines a value attribute of type int. Since the attribute is of type final, it needs to be assigned by a constructor. This logic is very simple and there is not much to pay attention to.
Conclusion: when constructing an Integer instance through the new keyword, the same as the instantiation of all ordinary objects is to allocate a space in the heap memory address.
Integer.valueOf#
The Integer.valueOf method converts a string to Integer type. The method is defined as follows
public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); }
This method calls another overloaded method, which is 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); }
It is found from this code that if the value of i is in the range of IntegerCache.low and IntegerCache.high, the Integer object instance is returned through the following code.
IntegerCache.cache[i+(-IntegerCache.low)];
Otherwise, use new Integer(i) to create a new instance object.
What is IntegerCache?
From its name, it is not difficult to guess that it should be related to the cache. The simple guess is: if the value of i is within a certain range, the object will be obtained directly from the cache.
The code definition of IntegerCache is 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 through system properties String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //If the high attribute value is configured, the largest of the two values is taken as the highest interval 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; //Traversal 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() {} }
The implementation logic of the above code is very simple:
- The value range of IntegerCache is: IntegerCache.low=-128, IntegerCache.hign=127, where hign can be adjusted through system parameters.
- Create an Integer array and initialize each value in this interval circularly.
Why is Integer designed like this? Whenever Cache is involved, it must be related to performance. In Integer, the commonly used value range is - 128 to 127. Therefore, in order to avoid frequent creation and destruction of objects for data within this range, a Cache is built. This means that for subsequent Integer instances not created through the new keyword, the values in this interval will be obtained from IntegerCache.
Problem solving #
Interview question: the difference between new Integer(112) and Integer.valueOf(112)
After understanding the above principle, it is easy to answer this question.
-
new Integer is to create an Integer object instance.
-
Integer.valueOf(112). Integer provides a Cache mechanism by default. For data in the range of - 128 to 127, it is not necessary to create a new object instance through the valueOf method, but only need to get it from the Cache.
Problem summary #
Integer has many deformed interview questions, one of which is typical.
There are two Integer variables A and B. after passing the swap method, exchange the values of a and B. 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 } }
Students with poor foundation may write programs directly according to the "correct logic". The possible codes are as follows.
private static void swap(Integer a,Integer b){ Integer temp=a; a=b; b=temp; }
In theory, there is no problem with program logic. Define a temporary variable to store the value of a, and then exchange a and b. the actual operation results are as follows
Before exchange: a=1,b=2 After exchange: a=1,b=2
Reflections on the re assignment of Integer objects #
Integer is an encapsulated object type. After passing the reference through the function, theoretically, a and b defined in the main method and a and b passed to the swap method point to the same memory address. Then, according to the implementation of the above code, it is also valid in theory.
There are two types of parameter passing in Java.
- Value transfer is a copy of data. The change of formal parameter value during method execution does not affect the value of actual parameter.
- Reference passing refers to the memory address. During method execution, since the address of the reference object points to the same block of memory, the modification of object data will affect the variables that reference the address.
The advantage of this design is to reduce the occupation of memory and improve access efficiency and performance.
So why does Integer, as an encapsulation type, pass a copy instead of a reference?
Let's take a look at the value definition in Integer. We can find that the attribute is final, which means it cannot be changed.
/** * The value of the {@code Integer}. * * @serial */ private final int value;
Conclusion: in Java, there is only one parameter transfer method, that is, value transfer. However, when a parameter is passed to a basic type, it is a copy of the value, and the modification of the copied variable does not affect the original variable; when a reference type is passed, it is a copy of the reference address, but the copied address and the real address point to the same real data, so the original variable can be modified When the Integer type is passed, although the copied reference address points to the same data, the Integer value cannot be modified, so the value in the original variable cannot be modified.
Therefore, the reason why the above code is not exchanged successfully is that a and b passed to the swap method will create a variable copy. Although the values in this copy have been exchanged, they will not affect the original value.
After understanding this knowledge, our problem becomes how to modify the data of an attribute modified with the final keyword. That is, it is implemented through reflection. The implementation 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); //For private modified variables, you need to set them through this method. field.set(a,b); field.set(b,temp); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
Can this code meet the expectations after running? The running results of the above program are as follows:
Before exchange: a=1,b=2 After exchange: a=2,b=2
From the results, it is true that there has been a change, but the change is not complete, because the expected value of b=1 did not appear. Why? In fact, it is related to the theme shared today. Let's take a step-by-step look.
- Integer temp=a. based on the principle of IntegerCache, a new temp instance will not be generated here, which means that the memory address pointed to by the temp variable and a variable is the same.
- When the value of a memory address is changed to b through reflection through the field.set method, the value of a should be 2. Note: since the value of memory address becomes 2 and the variable temp points to the memory address, the value of temp naturally becomes 2
- Then use file. Set (b, temp) to modify the value of b attribute. At this time, the value of temp is 2, so the result b becomes 2
private static void swap(Integer a,Integer b){ try { Field field=Integer.class.getDeclaredField("value"); Integer temp= a; field.setAccessible(true); //For private modified variables, you need to set them through this method. field.set(a,b); field.set(b,temp); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
After understanding the principle, we only need to modify the code Integer temp=a to the following way. Ensure that the temp variable is an independent instance.
Integer temp=new Integer(a);
After modification, the operation results are as follows
Before exchange: a=1,b=2 After exchange: a=2,b=1
Mic said: only when the basic skills are solid enough, can we see through the essence of any problem at a glance and be able to solve these problems easily.