首先我们要了解基本数据类型与包装类型。
包装类型
Java 语言是一个面向对象的语言,但是 Java 中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
包装类均位于 java.lang
包,包装类和基本数据类型的对应关系如下表所示
基本数据类型 | 包装类 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
在这八个类名中,除了 Integer 和 Character 类以后,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写即可。
扩展:为什么需要包装类?
因为java是一门面向对象的语言,在许多地方使用的是对象而不是基本数据类型,这时候就需要使用包装类了。例如,在集合类中,默认要求的是Object,无法将基本数据类型放入。
自动拆箱与装箱
这里的拆箱与装箱其实都是指的基本数据类型与包装类的转换,例如以int类型为例:
//装箱:
Integer i = new Integer(1);
//拆箱:
int j = i.intValue();
在 Java SE5 之前 ,都需要手动对数据转换进行装箱与拆箱,但是在Java SE5 之后,Java提供了自动装箱与拆箱。
上面代码可以简化成这样:
Integer i = 1;
int j = i;
在经过反编译后,有:
Integer i = Integer.valueOf(1);
int j = i.intValue();
从上面反编译后的代码可以看出,int 的自动装箱都是通过 Integer.valueOf()
方法来实现的,Integer 的自动拆箱都是通过 i.intValue` 来实现的。
在试验过其他类型后,发现其他类型也是通XXX.valueOf()方法实现自动装箱,使用XXXValue()方法来实现拆箱。
自动装拆箱常见场景
1. 将基本类型放入集合类中
List<Integer> list = new ArrayList<>();
int i = 1;
list.add(i);
反编译后:
List<Integer> list = new ArrayList<>();
int i = 1;
list.add(Integer.ValueOf(i));
2. 包装类型与基本类型比较
Boolean flag = false;
System.out.println(flag ? "阿云" : "阿戴");
反编译后:
Boolean flag = false;
System.out.println(flag.booleanValue() ? "阿云" : "阿戴");
3. 包装类型的运算
int a = 1;
Integer b = 2;
System.out.println(a + b);
反编译后:
int a = 1;
Integer b = 2;
System.out.println(a + b.intValue());
4. 三目运算符中
int a = 1;
Integer b = 2;
System.out.println(a > 0 : a : b);
反编译后:
int a = 1;
Integer b = 2;
System.out.println(a > 0 : a : b.intValue());
在三目运算符中,如果后面结果为基本类型和对象时,将会对对象进行自动拆箱,如果此时对象为null,则会报出空指针异常。
自动拆装箱与缓存
Integer integer1 = 3;
Integer integer2 = 3;
if (integer1 == integer2)
System.out.println("integer1 == integer2");
else
System.out.println("integer1 != integer2");
Integer integer3 = 300;
Integer integer4 = 300;
if (integer3 == integer4)
System.out.println("integer3 == integer4");
else
System.out.println("integer3 != integer4");
按理来说上面的两个判断的结果都是 false。虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个 if 判断都是 false 的。在 Java 中,==
比较的是对象引用,而 equals
比较的是值。所以,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都将返回 false。但其实,最后结果与想象有些小出入。
输出结果
integer1 == integer2
integer3 != integer4
原因就和 Integer 中的缓存机制有关。在 Java 5 中,在 Integer 的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。
-
适用于整数值区间-128 至 +127。
-
只适用于自动装箱。使用构造函数创建对象不适用。
如果一个变量p的值是:
-128至127之间的整数(§3.10.1)
true 和 false的布尔值 (§3.10.3)
‘\u0000’至 ‘\u007f’之间的字符(§3.10.4)
中时,将p包装成a和b两个对象时,可以直接使用a==b判断a和b的值是否相等。
自动拆装箱的缺点
- 包装对象的比较不能简单通过==,视情况使用equals
- 包装对象如果为null,自动拆装箱会报出控制住异常
- 如果在循环中存在拆装箱操作,将会浪费大量资源