Java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,装箱和拆箱可以让我们的代码更简洁易懂,本质是Java的语法糖。

  • 装箱: 基本类型 => 包装类型;
  • 拆箱: 包装类型 => 基本类型。

基本类型与包装类型对应

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

装箱拆箱的触发

​ 当表格中基础类型与它们的包装类有如下几种情况时,编译器会自动帮我们进行装箱或拆箱:

  • 进行 = 赋值操作(装箱或拆箱);
  • 进行+,-,*,/混合运算 (拆箱);
  • 进行>,<,==比较运算(拆箱);
  • 调用equals进行比较(装箱);
  • ArrayList,HashMap等包装类泛型对象,添加基础类型数据时(装箱).

例以下代码:

  1. Integer i = 100 等价于 Integer i = Integer.valueOf(100)
  2. int i = new Integer(100) 等价于 int i = new Integer(100).intValue()

容易踩坑的点

JVM缓存

如Integer类的valueOf(int)实现:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

可见,-128到127的Integer对象会被JVM缓存,所以有以下情况:

public static void main(String[] args) {
    // 等价于 Integer i1 = Integer.valueOf(100);
    Integer i1 = 100;
    Integer i2 = 100;
    Integer i3 = 200;
    Integer i4 = 200;

    System.out.println(i1 == i2);
    System.out.println(i3 == i4);
}

// -------------------输出-------------------
// true
// false

通过自动装箱,i1和i2指向cache中同一个对象,i3和i4指向两个对象。

valueOf的不同实现

以Double为例

public static void main(String[] args) {
    Double d1 = 1.0;
    Double d2 = 1.0;
    Double d3 = 11111.0;
    Double d4 = 11111.0;

    System.out.println(d1 == d2);
    System.out.println(d3 == d4);
}

// -------------------输出-------------------
// false
// false

至于具体原因,可见Double类的valueOf的实现。

public static Double valueOf(double d) {
    return new Double(d);
}

需要记住:

  • Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
  • Double、Float的valueOf方法的实现是类似的。

如此设计的原因:在某个范围内的整型数值的个数是有限的,而浮点数却不是。