我们知道,Java中基本数据类型及其对应的包装器类型如下:
基本数据类型 | 大小 | 包装器类型 |
---|---|---|
byte | 8bit | Byte |
char | 16bit | Character |
short | 16bit | Short |
int | 32bit | Integer |
long | 64bit | Long |
float | 32bit | Float |
double | 64bit | Double |
boolean | / | Boolean |
自动装箱与拆箱
那什么是自动装箱和拆箱呢?
简单来说,自动装箱其实就是自动将数据类型转成包装器类型,自动拆箱就是自动将包装器类型转成基本数据类型。
Integer x = 127;//装箱,调用了Integer.valueOf(127)来完成装箱操作
int y = x; //拆箱,调用了Integer.intValue()来自动完成拆箱操作
装箱过程就是调用包装器的valueOf(xxx)
方法来实现的,拆箱就是调用包装器的xxxValue()
方法来实现的。
Integer的valueOf()方法以及Integer缓存池实现如下:
如果数值i的范围在Integer缓存池取值范围内,就返回IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。Integer缓存池的默认范围是[-128, 127],这个上限是可以设置的。
其他基本数据类型和对应的包装器类型,可以同样去看它们的valueOf()
方法实现,可以发现:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的;Double、Float的valueOf方法的实现是类似的,没有涉及缓存池,每次调用返回的都是不同的对象引用。
相关面试题
面试中,我们可能会遇到这么一道题:
以下代码的输出结果是:
public class Main {
public static void main(String[] args) {
Integer x1 = 127;
Integer x2 = 127;
Integer x3 = 128;
Integer x4 = 128;
int x5 = 128;
int x6 = 128;
Double d1 = 127.00;
Double d2 = 127.00;
Character c1 = 'a';
Character c2 = 'a';
Boolean b1 = true;
Boolean b2 = true;
System.out.println(x1 == x2);//true, 127在Integer的缓存池范围内,多次调用取得的是同一对象的引用
System.out.println(x3 == x4);//false, 128不在Integer的缓存池范围内,多次调用取得的是不同对象的引用
System.out.println(x5 == x6);//true, 比较的是基本数据类型的值
System.out.println(x4 == x5);//true,
System.out.println(d1 == d2);//false, 每次调用Double.valueOf(double d) 都会new一个对象来返回
System.out.println(c1 == c2);//true
System.out.println(b1 == b2);//true
}
}
相信这个结果就很好理解了。
需要注意的是:
-
当 "=="运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
-
equals参数为包装类型,则先比较是否为同类型,非同类型直接返回false,同类型再比较值
-
==
VSequals()
==
判断两个对象是不是同一个对象(基本数据类型用 == 比较的是值,引用数据类型用 == 比较的是内存地址)euqals()
在没有重写的情况下,相当于通过==
比较两个对象;重写的情况下,一般是通过重写equals()
来判断两个对象的内容是否相等,相等就返回true(也就是说认为这两个对象相等)。
补充:String Pool
字符串常量池(String Pool)保存着所有字符串字⾯量(literal strings),这些字⾯量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。
当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在⼀个字符串和该字符串值相等(使用equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
当使用new关键字创建字符串对象时,String s1 = new String("aaa");
会创建两个字符串对象(前提是 String Pool 中还没有 “abc” 字符串对象):“abc” 属于字符串字面量,因此编译时期会在 String Pool 中创建⼀个字符串对象,指向这个 "abc"字符串字面量;使用new的方式会在堆中创建⼀个字符串对象。