自动装箱与拆箱的定义
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是,自动将包装器类型转换为基本数据类型
Java中的数据类型分为两类:一类是基本数据类型,另一类是引用数据类型
简单类型 | 二进制位数 | 封装器类 |
---|---|---|
int | 32 | Integer |
byte | 8 | Byte |
long | 64 | Long |
float | 32 | Float |
double | 64 | double |
char | 16 | Character |
boolean | 1 | Boolean |
上自动装箱代码
public static void main(String[] args) {
// TODO Auto-generated method stub
int a=3;
//定义一个基本数据类型的变量a赋值3
Integer b=a;
//b是Integer 类定义的对象,直接用int 类型的a赋值
System.out.println(b);
//打印结果为3
}
上面代码中的Integer b = a;就是我们所说的自动装箱的过程,上面代码在执行的时候调用了Integer.valueOf(int i)方法简化后的代码:
public static Integer valueOf(int i) {
if (i >= -128 && i <= 127)
return IntegerCache.cache[i + 127];
//如果i的值大于-128小于127则返回一个缓冲区中的一个Integer对象
return new Integer(i);
//否则返回 new 一个Integer 对象
}
可以看到Integer.valueOf(a)其实是返回了一个Integer的对象。因此由于自动装箱的存在Integer b = a这段代码是没有问题的,并且我们可以简化的来这样写:Integer b = 3;
同样也等价于这样写:Integer b = Integer.valueOf(3)。
上自动拆箱代码
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer b=new Integer(3);
//b为Integer的对象
int a=b;
//a为一个int的基本数据类型
System.out.println(a);
//打印输出3。
}
上面有一个:int a = b; 代码中把一个对象赋给了基本类型。其实这就等于int a = b.intValue()。
根据源码中可知道intValue是什么
public int intValue() {
return value;
}
这个方法就是返回了value值嘛,但是这里的value又是怎么一回事呢?继续找源码:
public Integer(int value) {
this.value = value;
}
原来这里的value就是,Integer后边括号里的值呀,于是我们的拆箱代码其实本质上是这样写的:
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer b=new Integer(3);
//b为Integer的对象
int a=b.intValue();
//其中b.intValue()返回实例化b时构造函数new Integer(3);赋的值3。
System.out.println(a);
//打印输出3。
}
范围概念
这里边是一个挺重要的知识点,至少我之前看的疯狂Java视频资料,以及我看的《Java编程思想》这本书,都有这方面的介绍。先看一个代码哈:
public static void main(String[] args) {
Integer a = 1000,b=1000;
Integer c=100,d=100;
System.out.println(a==b);
System.out.println(c==d);
}
原本我会以为是输出的是:true true啦,但是实际上不对,正确答案是false true。为甚呢?细细道来。
public static void main(String[] args) {
//1
Integer a=new Integer(123);
Integer b=new Integer(123);
System.out.println(a==b);//输出 false
//2
Integer c=123;
Integer d=123;
System.out.println(c==d);//输出 true
//3
Integer e=129;
Integer f=129;
System.out.println(e==f);//输出 false
//4
int g=59;
Integer h=new Integer(59);
System.out.println(g==h);//输出 true
}
第一部分输出false,很好理解,因为比较的是堆中指向的对象是不是同一个嘛,a,b是栈中对象的引用分别指向堆中的两个不同的对象。而a==b这条语句就是判断a、b在堆中指向的对象是不是统一个,因此输出为false。
第二部分输出true也很好理解,正是用了我们的自动装箱技术
我带大家这次仔细的看自动装箱的源码
public static Integer valueOf(int i) {
if (i >= -128 && i <= 127)
return IntegerCache.cache[i + 127];
//如果i的值大于-128小于127则返回一个缓冲区中的一个Integer对象
return new Integer(i);
//否则返回 new 一个Integer 对象
}
上面的代码中:IntegerCache.cache[i + 127]; 表示狠眼生,继续看代码:
private static class IntegerCache {
static final Integer cache[];
//定义一个Integer类型的数组且数组不可变
static {
//利用静态代码块对数组进行初始化。
cache = new Integer[256];
int j = -128;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
//cache[]原来是一个Integer 类型的数组(也可以称为常量池),value 从-128到127,
public static Integer valueOf(int i) {
if (i >=-128 && i <= 127)
return IntegerCache.cache[i + (-IntegerCache.low)];
//如果装箱时值在-128到127之间,之间返回常量池中的已经初始化后的Integer对象。
return new Integer(i);
//否则返回一个新的对象。
}
}
原来IntegerCache类在初始化的时候,生成了一个大小为256的integer类型的常量池,并且integer.val的值从-128~127,当我们运行Integer c = a(临时做的一个小栗子哈)的时候,如果-128 <= a <= 127,就不会再生成新的integer对象。于是我们第二部分的c和d指向的是同一个对象,所以比较的时候是相等的,所以我们输出true。
第三部分,理解如第二部分
第四部分:代码中g指向的是栈中的变量,h指向的是堆中的对象,但是我们的g == h为什么还是true呢?这就是自动插箱干的好事,g == h这代码执行的时候就是:g == h.IntValue(),而h.IntValue()=59,所以两边其实是两个int在比较而已。
总结
简单一句话:
装箱就是自动将基本数据类型转换为包装器类型;
拆箱就是自动将包装器类型转换为基本数据类型。