Java的自动装箱(Autoboxing)和拆箱(unboxing)

装箱和拆箱

    装箱-将基本数据类型转换为包装器类型;拆箱-包装器类型转换为基本数据类型。

基本类型 包装类型
int Integer
byte Byte
short Short
long Long
float Float
double Double
char Character
boolean Boolean

为什么需要装箱,拆箱

    Java包含基本数据类型和引用数据类型两种数据类型,在一些特殊情况下,如使用java.util.Collection类型时,我们想要创建一个基本类型的集合,但Collection的实现并不支持基本类型集合,所以只能创建对象的集合。如下:

ArrayList al = new ArrayList(); // not supported 
ArrayList al = new ArrayList(); // supported 
al.add(45); //auto Boxing

    所以装箱可以帮助我们处理一些特殊的只能使用引用类型的场合。

自动装箱和自动拆箱

    自动装箱是JDK5后,Java编译器在基础类型及其对应的包装器类之间进行的自动转换。
    在JDK5以前,生成一个Character对象需要这样做

Character ch = new Character('a');

    在JDK5之后,因为有了自动装箱,所以只需要这样

Character ch = 'a';

这个过程中会自动根据char创建对应Character对象,这就是自动装箱。反之自动拆箱的效果如下:

Integer i = 10;  //装箱
int n = i;   //拆箱

一些自动装箱和自动拆箱产生的问题

1.如下代码输出结果是什么?
public class Main {
    public static void main(String[] args) {
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

输出结果:

true
false 

原因:

    自动装箱实际上使用的包装类中的valueOf方法,如:Integer.valueOf(),其代码如下:

/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

    在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用,否则创建一个新的Integer对象,所以输出结果如上所示。感兴趣可以继续研究IntegerCache类。

Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Boolean值因为只有true和false两种,所以始终不重新创建对象
Double、Float由于区间是无限的所以不存在缓存,其valueOf方法会重新创建对象,无论值是多少,输出都为false

2.如下代码输出结果是什么?
public class Main {  
    public static void main(String[] args) {  
        int a = 7; 
        doSomething(a);
    }  
    
    private static void doSomething(double value){
        System.out.println("double = " + value);
    }
    
    private static void doSomething(Integer value){
        System.out.println("Integer = " + value);
    }
} 

输出结果:

double = 7

原因:

    对于int类型来说,既可以通过隐式强制转换转换为double,也可以通过自动装箱转换为Integer,但自动装箱是JDK5之后才加入的功能,所以这里的结果和JDK5前保持一致,从而优先隐式强制转换转

参考

Why do we use autoboxing and unboxing in Java?
深入剖析Java中的装箱和拆箱
Autoboxing and Unboxing

你可能感兴趣的:(Java的自动装箱(Autoboxing)和拆箱(unboxing))