1. 基本概念
装箱:自动将基本数据类型转化为引用类型包装起来
拆箱:将包装类型转换为基本数据类型;
//自动装箱
Integer total = 99;
//自动拆箱
int totalprim = total;
2. 过程
Integer total = 99;
执行上面那句代码的时候,系统为我们执行了:
Integer total = Integer.valueOf(99);
int totalprim = total;
执行上面那句代码的时候,系统为我们执行了:
int totalprim = total.intValue();
valueOf函数
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
首先它会判断i的大小,如果i小于等于-128(static final int low = -128;)或者大于等于128,就创建一个Integer对象,否则执行IntegerCache.cache[i + (-IntegerCache.low)];
Cache的计算
static final Integer cache[];
cache = new Integer[(high - low) + 1]; //low=-127, high=127 长度为256
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);//从-127到128
Cache是一个静态的数组对象,值从-127到128,共256个值
也就是说,
在i >= 128 || i < -128 下,会创建一个Integer对象,new Integer(i)
在i < 128 && i >= -128, 会根据i的值返回已经创建好的指定的对象(cache[i + 127])
例子
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2); //true
System.out.println(i3==i4); //false
}
}
再次解释,i1和i2等于100,那么就返回已经创建好的数组对象的值(cache[i + 127]),而i3和i4会分别创建一个对象,所以他们不相同。
又一个例子
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2); //false
System.out.println(i3==i4); //false
}
}
解释:
因为对于Integer,在(-128,128]之间只有固定的256个值,所以为了避免多次创建对象,我们事先就创建好一个大小为256的Integer数组,所以如果值在这个范围内,就可以直接返回我们事先创建好的对象就可以了。
但是对于Double类型来说,我们就不能这样做,因为它在这个范围内个数是无限的。
public static Double valueOf(String s) throws NumberFormatException {
return new Double(parseDouble(s));
}
总结:
Integer派别:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Double派别:Double、Float的valueOf方法的实现是类似的。每次都返回不同的对象。
Boolean类型
例子:
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);//true
System.out.println(i3==i4);//true
}
}
可以看到返回的都是true,也就是它们执行valueOf返回的都是相同的对象。
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
可以看到它并没有创建对象,因为在内部已经提前创建好两个对象,因为它只有两种情况,这样也是为了避免重复创建太多的对象。
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
自动装箱和拆箱操作
Integer num1 = 400;
int num2 = 400;
System.out.println(num1 == num2); //true
说明num1 == num2进行了拆箱操作
Integer num1 = 100;
int num2 = 100;
System.out.println(num1.equals(num2)); //true
equal比较的是内容本身,并且我们也可以看到equal的参数是一个Object对象,我们传入的是一个int类型,所以首先会进行装箱,然后比较,之所以返回true,是由于它比较的是对象里面的value值.
equals源码:
@Override
public boolean equals(Object o) {
return (o instanceof Integer) && (((Integer) o).value == value);
}
例子
Integer num1 = 100;
int num2 = 100;
Long num3 = 200l;
System.out.println(num1 + num2); //200
System.out.println(num3 == (num1 + num2)); //true
System.out.println(num3.equals(num1 + num2)); //fals
解释:
1、当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算
2. num3.equals(num1 + num2)为ture的条件是:
类型相同,内容相同
重点:
当 “==”运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)