一个对象的状态在对象被创建之后就不再变化,这就是所谓的不变模式。
----java与模式
不变模式在java中的应用
我们知道String是不可变类,在java中基础类型的包装类也都是不可变类。这里我们拿Integer进行举例。
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
Integer e = -128;
Integer f = -128;
Integer g = -129;
Integer h = -129;
System.out.println(a==b); //true
System.out.println(c==d); //false
System.out.println(e==f); //true
System.out.println(g==h); //false
// Integer与String 重写了 equals 方法,把它变成了值比较 所以输出为true
System.out.println(g.equals(h));
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
首先这里需要强调的就是,对于基本数据类型==比较的是值,而包装类明显是是个对象,这里涉及到自动装箱,大家不知道的可以去看一下拆箱/装箱。对于对象而言==比较的是对象的内存地址。但是对于对象我们平时基本上都采用equals()方法进行对象的比较。由于IntegerCache这个静态内部类,存储了[-128,127]的值的对象数组,缓存机制的作用就是提前实例化相应范围数值的包装类对象,只要创建处于缓存范围的对象,就使用已实例好的对象。从而避免重复创建多个相同的包装类对象,提高了使用效率。如果我们用的对象范围在[-128, 127]之内,就直接去静态区找对应的对象,如果用的对象的范围超过了这个范围,会帮我们创建一个新的 Integer 对象所以超过这个区间比较的地址就是false了,正是由于这种不可变机制,这个缓存数组得以在多个线程中进行共享,减少对象的创建。
当大量数据都在缓存区间的时候,就可以实现我们节省内存的目的。反过来,如果对象是可变的,那么一个内部对象值的变化会导致这个对象的引用是不安全的,所以每一次都要在堆开辟新的空间来确保对象的安全性。说白了包装类的缓存机制主要就是减少对象的创建来节省内存。
包装类和基本数据类型的区别
默认值不同
包装类的默认值是null,而基本数据类型是对应的默认值(比如整型默认值是0,浮点型默认值是0.0)
存储区域不同
基本数据类型是把值保存在栈内存里,包装类是把对象放在堆中,然后通过对象的引用来调用他们
传递方式不同
基本数据类型变量空间里面存储的是值,传递的也是值,一个改变,另外一个不变,而包装类属于引用数据类型,变量空间存储的是地址(引用),传递的也是引用,一个变,另外一个跟着变。