可能一眼看不懂的几行 Kotlin 代码,程序员面试防坑宝典
同时我们在末尾再加上一段测试代码,采用直接new
的方式构建对象,得到的比较结果为false
。
int c= 100;Integer cBox = new Integer(c);Integer cAnotherBox = new Integer(c);System.out.println(cBox == cAnotherBox); // false
原理
基础知识
Kotlin 中三等号(===) 比较的是两个引用在内存中指向的是不是同一对象(即同一内存空间),双等号(==) 比较的是值;
Kotlin 中的非空 Number 类型对应到 JVM 平台是基本类型:int,double 等等;
Kotlin 中的可空 Number 类型对应到 JVM 平台是封装类型:Integer,Double 等等;
Java 中双等号(==)比较的是两个引用在内存中指向的是不是同一对象(即同一内存空间);
Kotlin 中三等号等价于 Java 中的双等号;
字节码分析
val a: Int = 100
L0LINENUMBER 12 L0BIPUSH 100ISTORE 1
val boxedA: Int? = aval anotherBoxedA: Int? = a
L1LINENUMBER 13 L1ILOAD 1INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;ASTORE 2L2LINENUMBER 14 L2ILOAD 1INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;ASTORE 3
从字节码不难看出,非空 Int 型数据,直接使用BIPUSH
压栈(取值 -128~127 时,JVM 采用 BIPUSH 指令将常量压栈)。而针对非空 Int 型变量赋值给可空 Int 型声明,是通过 Integer
类的 public static Integer valueOf(int i)
方法实现。
查看 Integer
类中 public static Integer valueOf(int i)
方法源码:
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
看到 IntegerCache
的一瞬间感觉一切都清晰了。JDK 从 1.5 版本开始,把 -128~127(high的默认值)
的数字缓存起来了,用于提升性能和节省内存,通过 -XX:AutoBoxCacheMax=<size>
来控制 high 的取值。所以,当数字在缓存范围内时,通过valueOf()
方式拿到的对象引用全部来自于缓存列表,所以对于相同的值,对象引用相同;若是超过缓存范围,则是重新生成的对象,自然也就不相等了。此时回头看开头的两段 Kotlin 代码和我们改写的 Java 代码,就很清晰了。
/**
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 i
nt high;static final Integer cache[];
static {// high value may be configured by propertyint 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_VALUEh = 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() {}}
IDEA 配置调整 high 值
通过配置
-Djava.lang.Integer.IntegerCache.high=<size>
或者-XX:AutoBoxCacheMax=<size>
调整阈值。
延伸
除了 Integer
类,Character
、Byte
、 Short
、 Long
等类型也有类似的缓存,只是除了 Integer
外,其他类的缓存范围是不可变的。
private static class ByteCache {private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
评论