装箱与拆箱的过程时自动进行的,因此称为“自动装箱”、“自动拆箱”,属于编译期的语法糖。
以基本类型int与包装类型Integer为例讨论。既然是编译期的语法糖,那么直接分析编译出来的字节码即可,可以使用jad工具(估计内部封装了javap一类的工具)。
public static void main(String[] args){
Integer boxing = 1;
}
jad解析class文件,发现根据字节码反编译为 Integer.valueOf(int)
方法:
public static void main(String args[]){
Integer boxing = Integer.valueOf(1);
// 0 0:iconst_1
// 1 1:invokestatic #2 <Method Integer Integer.valueOf(int)>
// 2 4:astore_1
// 3 5:return
}
这是一个静态工厂方法,内部最终调用了Integer类的构造器 Integer.<init>(init)
:
public static Integer valueOf(int i){
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
特别的,Integer类默认缓存 -128~127
的包装对象(上界可通过 java.lang.Integer.IntegerCache.high
参数配置,最小127)。因此,缓存范围内的包装对象来自缓存的常量池,相同value包装对象的引用相等;缓存范围外的包装对象的引用均不相等。
public static void main(String[] args){
int unboxing = new Integer("2");
}
拆箱的时候编译为 Integer.intValue()
方法:
public static void main(String args[]){
int unboxing = (new Integer("2")).intValue();
// 0 0:new #2 <Class Integer>
// 1 3:dup
// 2 4:ldc1 #3 <String "2">
// 3 6:invokespecial #4 <Method void Integer(String)>
// 4 9:invokevirtual #5 <Method int Integer.intValue()>
// 5 12:istore_1
// 6 13:return
}
该方法直接返回内部值 Integer#value
:
public int intValue(){
return value;
}
陷阱主要出现在包装类型与基本类型混用的场景中。
以“ ==
”为例:
因此,如果要比较包装类型是否相等,最好显示的使用equals方法。
另外,如果是算术运算、除“ ==
”外的逻辑运算、位运算等,则统一拆箱为基本类型再运算;有抛出NullPointerException的危险。