1.对象包装器整体类结构
自动装箱和拆箱.png
2.什么自动装箱和拆箱机制
自动装箱:把基本数据类型转换为包装类类型的过程,称为自动装箱;
自动拆箱:把包装类类型转换为基本数据类型的过程,称为自动拆箱。
Integer i = 10;//装箱
int n = i;//拆箱
3.自动装箱拆箱底层实现原理
以Integer为示例,其他包装器原理类似。Ok,Show me code,Talk is cheap!
public class WrapperTest {
public static void main(String[] args) {
Integer integer = 10;
int i = integer;
}
}
通过javac WrapperTest.java编译得到WrapperTest.class文件,在通过javap -c -verbose WrapperTest.class得到下图编译信息。
装箱和拆箱反编译解析.png
从图中可以看出,Java自动装箱时调用的是Integer的valueOf(int)方法,而在自动拆箱时调用的事Integer的intValue()方法。
4.包装器核心源码解析
(1)Integer包装器核心源码解析
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
此方法返回表示指定的int值的Integer实例。如果不需要新的Integer实例,则应优先于Integer(int)构造方法使用此方法。因为该方法通过缓存频繁请求的值,可显著提高空间和时间性能。而且,此方法始终缓存[-128,127]范围内的值,并可能缓存该范围之外的其他值。
/**
* 核心内部类
*/
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() {}
}
缓存以支持JLS要求的[-128,127]范围内的值的自动装箱的对象标识语义。首次使用时会初始化缓存。 缓存的大小可以由 -XX:AutoBoxCacheMax = 选项控制。 在VM初始化期间,可以在sun.misc.VM类的私有系统属性中设置并保存java.lang.Integer.IntegerCache.high属性。
通过以上两段源码可以得知,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用,否则创建一个新的Integer对象。
(2)Double包装器核心源码解析
public static Double valueOf(double d) {
return new Double(d);
}
public Double(double value) {
this.value = value;
}
此方法返回表示指定的double值的Double 实例。如果不需要新的Double实例,则应优先于Double(double)构造方法使用此方法。因为该方法通过缓存频繁请求的值,可显著提高空间和时间性能。
(3)Boolean包装器核心源码解析
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
/**
* Returns a {@code Boolean} instance representing the specified
* {@code boolean} value. If the specified {@code boolean} value
* is {@code true}, this method returns {@code Boolean.TRUE};
* if it is {@code false}, this method returns {@code Boolean.FALSE}.
* If a new {@code Boolean} instance is not required, this method
* should generally be used in preference to the constructor
* {@link #Boolean(boolean)}, as this method is likely to yield
* significantly better space and time performance.
*
* @param b a boolean value.
* @return a {@code Boolean} instance representing {@code b}.
* @since 1.4
*/
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
5.常见面试题
public class WrapperTest {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = new Integer(100);
Integer i4 = 200;
Integer i5 = 200;
Integer i6 = new Integer(200);
System.out.println(i1 == i2);// true
System.out.println(i1 == i3);// false
System.out.println(i4 == i5);// false
System.out.println(i4 == i6);// false
Double d1 = 100.0;
Double d2 = 100.0;
Double d3 = new Double(100.0);
Double d4 = 200.0;
Double d5 = 200.0;
Double d6 = new Double(200.0);
System.out.println(d1 == d2);// false
System.out.println(d1 == d3);// false
System.out.println(d4 == d5);// false
System.out.println(d4 == d6);// false
Boolean b1 = false;
Boolean b2 = false;
Boolean b3 = true;
Boolean b4 = true;
System.out.println(b1 == b2);// true
System.out.println(b3 == b4);// true
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c == d);// true
System.out.println(e == f);// false
System.out.println(c == (a + b));// true
System.out.println(c.equals(a + b));// true
System.out.println(g == (a + b));// true
System.out.println(g.equals(a + h));// true
}
}
6.总结
自动装箱:把基本数据类型转换为包装类类型的过程,称为自动装箱;自动拆箱:把包装类类型转换为基本数据类型的过程,称为自动拆箱。
自动装箱过程是通过调用包装器的valueOf方法实现的,自动拆箱是通过调用包装器的xxxValue方法实现的。(xxx代表对应的基本数据类型)
当==运算符的两个操作数都是包装类时比较的是它们是否指向同一个引用,但如果其中有一个操作数是表达式(包含算术运算)则比较的是数值(即触发自动拆箱的过程)。
对于包装类,equals方法并不会进行类型转换。
原创不易,如需转载,请注明出处@author Davince!