Java为每个基本数据类型(primitive data type)都生成了一个包装类型(wrapper class)。
对应关系
基本类型 | 包装类型 | 基本类型 | 包装类型 |
---|---|---|---|
byte | Byte | float | Float |
short | Short | double | Double |
int | Integer | char | Character |
long | Long | boolean | Boolean |
除int和char的包装类型外,其他包装类型的类名都是将基本类型的首字母转为大写。
自动装箱与拆箱
先弄清楚两个概念
1.装箱(boxing):将基本数据类型转换为包装类型。
2.拆箱(unboxing):将包装类型转换为基本数据类型。
自动装箱(AutoBoxing)和自动拆箱(AutoUnboxing)就是由JVM自动实现上述的转换。以int和Integer为例
1 | public class Main { |
自动装箱与拆箱的实现原理
查看字节码
使用javap -c Main.class
对上述代码进行反汇编,得到了如下结果:
1 | Compiled from "Main.java" |
1.在第12行,调用了Integer类的静态方法valueOf,该方法用于将int型数据转换为Integer类型。
1 | public static Integer valueOf(int i) |
2.在第15行,调用了Integer类的普通方法intValue(),该方法用于将Integer类型转换为int型。
1 | public int intValue() |
反编译
如果对字节码指令不熟悉,我们还可以使用反编译工具,例如JD-GUI,将字节码反编译为Java代码。反编译的结果如下
1 | public class Main { |
分析
通过之前的探索,我们不难发现:自动装箱与拆箱,在编译之后被转化成了对应的包装(valueOf)和还原(xxxValue)方法。
数据类型 | 包装方法 | 还原方法 | 数据类型 | 包装方法 | 还原方法 |
---|---|---|---|---|---|
Byte | valueOf | byteValue() | Float | valueOf | floatValue() |
Short | valueOf | shortValue() | Double | valueOf | doubleValue() |
Integer | valueOf | intValue() | Character | valueOf | charValue() |
Long | valueOf | longValue() | Boolean | valueOf | booleanValue() |
包装类型中的缓存
接下来,仍以Integer为例。
缓存分析
首先,我们来看看如下的代码,不妨猜测下输出的结果是什么?
1 | public class Main { |
如果对包装类型中的缓存不熟悉,可能会觉得应该输出两个true。可是,事实又是怎样呢?实际的输出结果如下:
1 | true |
怎么会这样呢?事实上,在Integer类中有一个静态内部类IntegerCache
1 | private static class IntegerCache { |
默认情况下,IntegerCache在初始化时,缓存了从-128~127这256个数字。
接下来,我们再看看Integer的包装方法valueOf(int i):
1 | public static Integer valueOf(int i) { |
当给定的整数位于-128~127之间时,不会创建新的Integer实例,而是直接从缓存中读取。
缓存范围
数据类型 | 缓存范围 | 数据类型 | 缓存范围 |
---|---|---|---|
Byte | -128~127 | Float | —— |
Short | -128~127 | Double | —— |
Integer | -128~127 | Character | 0~127对应的Unicode编码 |
Long | -128~127 | Boolean | true和false |
equals方法
假设有如下代码,我们可以猜测下输出的结果是什么?
1 | public class Main { |
输出结果:
1 | true |
为什么会这样呢?使用==时相等,而使用equals方法却有可能不相等。
原因在于包装类型的equals方法不会处理数据转型。以Integer类为例,其equals源码如下
1 | public boolean equals(Object obj) { |
可以看到,当输入的类型是Integer时,比较二者的value是否相等;否则,直接返回false。