特性列表
-
自动化拆箱与装箱
-
枚举
-
泛型
-
增强for循环
-
可变参数
-
注解
-
静态导入
-
线程池
-
Generics 类
-
元数据
-
协变返回类型
拆箱与装箱
java语言从设计之初就标识其为面向对象的一门语言,并提供了4类八种基本数据类型,在设计时每种基本类型均对应了相应的包装类型:
int | Integer |
---|---|
byte | Byte |
short | Short |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
什么是拆箱,什么又是装箱?
拆箱与装箱,这两个名称很容易让人联想到工厂车间中流水线上包装产品和打开产品时的两个常见操作,举个栗子:我们每个开发人员用到的笔记本电脑,背后需要有对应的生产厂家来负责生产组装,当电脑生产组装完毕不是直接拿到了市场上就行销售,此时会给该电脑打上标签,型号并进行打包便于后续运输和销售,而对于购买用户来说,我们在网上下过单后拿到的也不是一个裸机,我们拿到的是被厂商包装过得一台电脑产品,此时,激动的你会小手颤抖的小心打开电脑包装盒,里面有厂商给你打包好的电脑,电源,说明书等,说到这里,相信大家对于装箱与拆箱过程有整体了解。
为什么需要自动装箱与拆箱?
Java早年设计的一个缺陷,基本数据类型不是对象,自然不是Object的子类,
需要装箱才能把数据类型变成一个类,那就可以把装箱过后的基本数据类型当做一个对象,就可以调用object子类的接口。而且基本数据类型是不可以作为形参使用的,装箱后就可以满足使用了。
Jdk1.5 引入了基本类型自动化的装箱与拆箱新特性,这两个操作不需要开发人员在负责代码的处理,而是交给编译器来自动化实现,想想是不是很美?
Jdk 对于装箱与拆箱的定义描述:
装箱:程序在运行时自动将基本数据类型转换为包装类型;
拆箱:程序在运行时自动将包装类型转换为基本数据类型。
代码演示
Java5之前拆箱与装箱示例代码((这里以Integer类型为例,其他类型同样适用,读者自行验证)):
/**
* Java5之前拆箱与装箱代码示例
*/
public static void test_boxing_unboxing_4(){
/**
* Java5 之前得到一个2048的包装对象
* 需要通过手动方式借助带参构造器 构造2048 Integer 对象
*/
Integer i=new Integer(2048);
System.out.println(i);
/**
* Java5 之前由包装类型得到一个2048的基本类型
* 通过调用Integer包装对象intValue方法获取整数2048
*/
int h=i.intValue();
System.out.println(h);
}
Java5之后拆箱与装箱示例代码:
public static void main(String[] args) {
/**
* 自动化装箱:程序在运行时自动将基本数据类型转换为包装类型;
* Java5开始提供了自动装箱功能
* 比如我要定义一个2048的整型对象 从Java5 开始就可以这样来编写你的代码
* 这个过程程序在运行中会自动根据我们提供的2048数字创建一个Integer对象
*/
Integer i=2048;// 装箱
System.out.println(i);
/**
*自动化拆箱:程序在运行时自动将包装类型转换为基本数据类型。
* Java5开始提供了自动装箱功能
* 比如我要定义一个1024的整型对象l 此时程序在运行时就会产生装箱操作
* 后续定义变量x 值为l 此时Integer 类型的l变量会将自已引用的1024数值赋给x 这个过程就是拆箱
*/
Integer l=1024;// 装箱
int x=l;// 拆箱
System.out.println(x);
}
从以上代码可以看出 Java5 之后对于基本数据类型的装箱与拆箱的代码变得相当简洁,大大简化了我们平时开发代码量。
装箱与拆箱实现
在项目编译目录下执行 通过反编译命令 javap -c,编译对应class 文件 如下图:
可以看得到:Java5 之后实现自动化装箱 内部实际上执行的是valueof 方法 ,而自动化拆箱内部执行的为intValue方法。
自动装箱与拆箱面试常见“坑”
-
Integer 比较问题
public static void test_autoboxing_unboxing(){
Integer b1 = 66;
Integer b2 = 66;
Integer b3 = 201;
Integer b4 = 201;
System.out.println(b1 == b2);// true or false?
System.out.println(b3 == b4);// true or false?
}
这里第一个输出为true,而第二个输出为false。
答案可以从源码分析得到:当数字在-127 ~128 之间时返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
-
Double 比较问题
public static void test_autoboxing_unboxing02(){
Double b1 = 66.0;
Double b2 = 66.0;
Double b3 = 201.0;
Double b4 = 201.0;
System.out.println(b1==b2);
System.out.println(b3==b4);
}
这里两次输出均为false。
答案可以从源码分析得到每次得到的double 对象均是一个新创建后的对象,变量的地址是不一样的,那为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现?很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是
注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。Double、Float的valueOf方法的实现是类似的。