Caching Mechanism for Java Wrapper Types
Integer caching mechanism
background
The most common interview question for Integer is to ask how the values of Integer compare equal. for example:
Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);// 输出 true
Integer i1 = 33;
Integer i2 = new Integer(33);
System.out.println(i11 == i22);// 输出 false
Integer i1 = new Integer(33);
Integer i2 = new Integer(33);
System.out.println(i3 == i4);// 输出 false
Integer i1 = 129;
Integer i2 = 129;
System.out.println(i1 == i2);// 输出 false
Source code analysis
The first few may be easy to understand, mainly because the last one is 129, why is it still output false, this is the cache mechanism of Integer, let's look at the source code of Integer.
/**
* 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=<size>} 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++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {
}
}
It can be seen from the static internal class of this cache that the cache value of Integer is from -128 to 127. Let's take a look at the bytecode file content of the compiled class file in the example just now:
// class version 52.0 (52)
// access flags 0x21
public class com/example/demoweb/controller/tt {
// compiled from: tt.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 7 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/example/demoweb/controller/tt; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V
// parameter args
L0
LINENUMBER 9 L0
SIPUSH 129
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
ASTORE 1
L1
LINENUMBER 10 L1
NEW java/lang/Integer
DUP
SIPUSH 129
INVOKESPECIAL java/lang/Integer.<init> (I)V
ASTORE 2
L2
LINENUMBER 11 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
ALOAD 1
IF_ACMPNE L3
ICONST_1
GOTO L4
L3
FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer] [java/io/PrintStream]
ICONST_0
L4
FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer] [java/io/PrintStream I]
INVOKEVIRTUAL java/io/PrintStream.println (Z)V
L5
LINENUMBER 14 L5
RETURN
L6
LOCALVARIABLE args [Ljava/lang/String; L0 L6 0
LOCALVARIABLE i1 Ljava/lang/Integer; L1 L6 1
LOCALVARIABLE i2 Ljava/lang/Integer; L2 L6 2
MAXSTACK = 3
MAXLOCALS = 3
}
We can see Integer i1 = 129;
that what the bytecode actually executes is valueOf
the method
L0
LINENUMBER 9 L0
SIPUSH 129
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
ASTORE 1
L1
Look at valueof
the source code of the method
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Get it from the cache first, if you can’t get it from the cache, you will create a new object. The 129 here is not in the cache, so i1
and i2
are two different objects, so the comparison is false.
Reflection: How do Integer values compare?
Let's look at the method again equals
:
public boolean equals(Object obj) {
//先判断对象是不是int类型,是则比较的是int值,而不是比较两个对象
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Therefore, the comparison of the Integer type needs to be usedequals
Long caching mechanism
With Integer
the basis of caching, in fact, Long
the packaging type is also the same operation, let's look directly at the source code:
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) {
// will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
private static class LongCache {
private LongCache(){
}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
Long
The cache range of the type opened from the source code is also -128-127
a value between
other basic types
Byte
, Short
, Integer
, Long
These four wrapper classes create the corresponding type of cache data with the value [-128, 127]Character
by default, create the cache data with the value in the range of [0,127]Boolean
, and directly return True
or False
.