自动装箱与拆箱 - morris131/morris-book GitHub Wiki
八种基本数据类型(byte,short,char,int,long,float,double,boolean)对应八种包装类型(Byte,Short,Charactor,Integer,Long,Float,Double,Boolean)。
装箱是自动将基本数据类型转换为包装器类型;拆箱是自动将包装器类型转换为基本数据类型。
Integer i = 10; //装箱
int n = i; //拆箱
以Interger类为例,下面看一段代码:
package com.morris.base;
public class AutoPackingTest {
public static void main(String[] args) {
Integer m = 10;
int n = m;
}
}
对编译后的class文件使用Java Decompiler进行反编译:
package com.morris.base;
public class AutoPackingTest
{
public static void main(String[] args)
{
Integer m = Integer.valueOf(10);
int n = m.intValue();
}
}
从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法,,而在拆箱的时候自动调用的是Integer的intValue方法。
总结:装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。
package com.morris.base;
public class PackingEqualTest {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
Integer i = new Integer(1);
System.out.println(c == d);
System.out.println(e == f);
System.out.println(c == (a + b));
System.out.println(c.equals(a + b));
System.out.println(g == (a + b));
System.out.println(g.equals(a + b));
System.out.println(g.equals(a + h));
System.out.println(i == a);
}
}
运行结果如下:
true
false
true
true
true
false
true
false
反编译结果如下:
package com.morris.base;
import java.io.PrintStream;
public class PackingEqualTest
{
public static void main(String[] args)
{
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(2);
Integer c = Integer.valueOf(3);
Integer d = Integer.valueOf(3);
Integer e = Integer.valueOf(321);
Integer f = Integer.valueOf(321);
Long g = Long.valueOf(3L);
Long h = Long.valueOf(2L);
Integer i = new Integer(1);
System.out.println(c == d);
System.out.println(e == f);
System.out.println(c.intValue() == a.intValue() + b.intValue());
System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));
System.out.println(g.longValue() == a.intValue() + b.intValue());
System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));
System.out.println(g.equals(Long.valueOf(a.intValue() + h.longValue())));
System.out.println(i == a);
}
}
Integer中有个静态内部类IntegerCache,里面有个cache[],也就是Integer常量池,常量池的大小为一个字节(-128~127),可以使用JVM的启动参数(-XX:AutoBoxCacheMax=size)设置最大值。
/**
* 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 -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) {
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);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
所有整数类型的类都有类似的缓存机制:Byte,Short,Long 的缓存池范围默认都是:-128到127。可以看出,Byte的所有值都在缓存区中,用它生成的相同值对象都是相等的。所有整型(Byte,Short,Long)的比较规律与Integer是一样的。同时Character对象也有CharacterCache缓存池,范围是0到127。除了Integer可以通过参数改变范围外,其它的都不行。
Integer重写了Object的equals()方法,比较时会自动拆箱。
/**
* Compares this object to the specified object. The result is
* {@code true} if and only if the argument is not
* {@code null} and is an {@code Integer} object that
* contains the same {@code int} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}