一. 引出包装类中的缓存设计
首先我们看一段神奇的代码:
class CacheDemo
{
public static void main(String[] args)
{
// 装箱:方式1
Integer num1 = new Integer(123);
Integer num2 = new Integer(123);
System.out.println(num1==num2); // false
//装箱:方式2
Integer num3 = Integer.valueOf(123);
Integer num4 = Integer.valueOf(123);
System.out.println(num3==num4); // true
// 自动装箱
Integer num5 = 123;
Integer num6 = 123;
System.out.println(num5==num6); // true
System.out.println("-------------------------------------");
// 装箱:方式1
Integer num11 = new Integer(250);
Integer num22 = new Integer(250);
System.out.println(num11==num22); // false
//装箱:方式2
Integer num33 = Integer.valueOf(250);
Integer num44 = Integer.valueOf(250);
System.out.println(num33==num44); // fasle
// 自动装箱
Integer num55 = 123;
Integer num66 = 123;
System.out.println(num55==num66); // true
}
}
---------- 运行java ----------
false
true
true
-------------------------------------
false
false
true
输出完成 (耗时 0 秒) - 正常终止
为什么会出现以上结果,我们来逐个分析:
1. System.out.println(num1==num2);
num1和num2是两个Integer对象,“==” 比较的是两个对象的地址,显然为false
2. System.out.println(num3==num4);
num3和num4是通过装箱方式2 valueOf来创建的,我们来看下valueOf的源码:
缓存中的值 :-128 ≤ value ≤ 127
,超过这个范围就会重新创建一个对象,而在我们代码中,num3和num4都为123,在这个范围内,因此,没有创建新的对象,所有num3==num4为true;
3.
System.out.println(num5==num6);
创建num5和num6采用的是自动装箱的方式,在之前讲解基本类型的包装类博客中提到,自动拆箱和装箱是一个语法糖/编译器级别新特性。在底层依然是手动装箱和拆箱操作。但是,装箱操作使用的是Integer.valueOf的方式,而不是直接new Integer。因此与2中方式相同,num5==num6结果页为true.
4.
System.out.println(num11==num22);
num11和num22是两个Integer对象,“==”比较的是两个对象的地址,显然为false。
5.
System.out.println(num33==num44);
num33和num44的值为250,不再缓存范围[-128,127]内,因此num22和num33是两个不同的对象,显然为false。
6.
System.out.println(num55==num66);
原因同5
二. 包装类中的缓存
包装类的缓存设计,又称为享元设计:
就是创建一个缓存区(有限定大小的)来将重复使用的数据放进去,从而达到少占用内存空间的效果。
包装类缓存大小:
除了Character包装类是:0-127之间,其余(Integer,Long等)都是-128-127之间。
一旦超过缓存空间,则系统会在堆内存中new一个新的对象出来。
包装类的缓存设计(享元模式),本质就是缓存设计:
Byte,Short,Integer,Long:缓存[-128,127]区间的数据;
Character:缓存[0,127]区间的数据.
1. Double中没有缓存
Double d1 = 1.0;
Double d2 = 1.0;
System.out.println(d1==d2); // fasle
2. Float没有缓存
Float f1 = 1.3f;
Float f2 = 1.3f;
System.out.println(f1==f2); // fasle
3. Character只对[0,127]具有数据缓存功能
Character c1 = 1;
Character c2 = 1;
System.out.println(c1==c2); // true
4. Boolean数据缓存只有TRUE 和FALSE
Boolean b1 = false;
Boolean b2 = false;
System.out.println(b1==b2);
总结:
Byte (缓存范围:[-128,127])
Short (缓存范围:[-128,127])
Long (缓存范围:[-128,127])
Integer (缓存范围:[-128,127])
Character (缓存范围:[0,127])
Boolean (全部缓存)
Float (没有缓存)
Doulbe (没有缓存)
三. 如何比较包装类型中的值
如果使用包装类存储的值超过缓存范围,如何比较它们值是否相同?
采用equals方法
Integer num1 = 123;
Integer num2 = 123;
System.out.println(num1.equals(num2));
在之前的博文中,我们就已经讲到,子类都应该覆盖父类中(Object)的equals方法,从而比较我们想关心的数据。我们来看下Integer中equals方法,其实就是把包装类型进行了拆箱,然后比较基本数据类型的值。
所以,在今后我们比较包装类型的值时,统统采用equal方法。