Java基础之包装类的自动装箱和拆箱详解

时间:2020-12-05 19:27:03

定义

在java中,数据类型可以分为两大类,即基本数据类型和引用数据类型,基本数据类型的数据不是对象,所以对于要将数据类型作为对象来使用的情况,java提供了相对应的包装类。(关于包装类的详细介绍请参看博客Java基础之常用类详解

本篇博客主要讲述包装类的自动装箱和拆行机制。

所谓装箱,就是把基本数据类型用它们相对应的引用类型包起来,使它们可以具有对象的特质,如我们可以把int类型包装成Integer类型的对象,或者把double包装秤Double,等等。

所谓拆箱,就是和装箱的方向相反,将Integer即Double这样的引用类型的对象重新简化成基本数据类型的数据。

而java JDK引入的自动装箱和拆箱就是编译器来依据我们编写的代码,决定是否进行装箱和拆箱动作。即无需使用valueOf()和intValue()等方法。(如果这方面不熟悉请参看博客Java基础之常用类详解

关于自动装箱拆箱机制的注意事项

这是本篇博客要讲述的重点

先看一个小例子:


public class WrapperText {

public static void main(String[] args) {
Integer a = 100;
Integer b = 100;

Integer c = 200;
Integer d = 200;

System.out.println(a == b);//1
System.out.println(a == 100);//2

System.out.println(c == d);//3
System.out.println(c == 200);//4
}

}

如果我们对于Java中自动装箱和拆箱操作了解不够深入的话,一定会这么想:自动装箱后,abcd都是Integer对象的不同引用,“==”操作符又是用来比较对象引用的,所以1和3都应输出false。而对于2和4,由于a和c都进行了自动拆箱,因此其比较是基本数据类型的比较。“==”操作符比较的使它们的值,所以2和4因该输出true。即最终结果输出:
false
true
false
true
但是正确的结果却是:
Java基础之包装类的自动装箱和拆箱详解
我们看到1的结果为true,3的结果为false,这是为什么呢。其实很简单,自动装箱过程其实是调用了valueOf()的方法,而valueOf()方法的源码为:

public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
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() {}
}

通过阅读源代码,可以发现,java内部为了节省内存,IntegerCache类中有一个数组缓存了值从-128到127的Integer对象。当我们调用Integer.valueOf(int i)的时候,如果i的值时结余-128到127之间的,会直接从这个缓存中返回一个对象,否则就new一个新的Integer对象。因此,1为true,3为false。

最后分享一道与之相关的很有意思的题目:

请提供一个对i的声明,将下面的循环转变成为一个无限循环:

while(j <= i && i <= j && i != j){

}

相信如果仔细阅读了本篇博客,这道题一定能够很轻松的解决。