如果程序经常需要使用相同的不可变实例,则可以考虑缓存这种不可变类的实例,下面是一个实现了不可变类实例的缓存
/**
* @author 张家琛
* @version 1.0
* @date 2023/1/24 23:37
*/
public class CacheImmutable {
private static int MAX_SIZE = 20;
//使用数组缓存已有的实例
private static CacheImmutable[] cache = new CacheImmutable[MAX_SIZE];
//记录缓存实例在缓存中的位置,cache[pos-1]是最新缓存的实例
private static int pos = 0;
private final String name;
private CacheImmutable(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static CacheImmutable valueOf(String name) {
//先遍历看看是否已经缓存过
for (int i = 0; i < MAX_SIZE; i++) {
if (cache[i] != null && cache[i].getName().equals(name)) {
return cache[i];
}
}
//之前没缓存过
if (pos == MAX_SIZE) { //缓存已经满了,把缓存的第一个对象覆盖,把刚生成的放在缓存池最开始位置
cache[0] = new CacheImmutable(name);
pos = 1;
} else {//缓存没满,创建对象缓存起来,pos++
cache[pos] = new CacheImmutable(name);
pos++;
}
return cache[pos - 1];
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == CacheImmutable.class) {
var ci = (CacheImmutable) obj;
return name.equals(ci.getName());
}
return false;
}
public int hashCode() {
return name.hashCode();
}
}
测试类:
class Test {
public static void main(String[] args) {
var c1 = CacheImmutable.valueOf("111");
var c2 = CacheImmutable.valueOf("111");
System.out.println(c1 == c2);
}
}
运行结果:
这种设计模式也在很多地方被利用,例如java.lang.Integer类,如果使用new构造Integer对象,则每次返回新的;如果采用valueOf()方法来创建Integer对象,则会缓存该方法创建的对象。
由于用new构造Integer对象不会启用缓存,性能较差,Java9已经将该构造器标记为过时了
Integer测试案例:
var integer1 = new Integer(7);
var integer2 = Integer.valueOf(7);
var integer3 = Integer.valueOf(7);
System.out.println(integer1 == integer2);
System.out.println(integer2 == integer3);
var integer4 = Integer.valueOf(128);
var integer5 = Integer.valueOf(128);
System.out.println(integer4 == integer5);
运行结果:
Integer默认只缓存-128~127之间的Integer对象,因此超过这个范围之外的都将不缓存,这个范围可以修改虚拟机参数 -XX:AutoBoxCacheMax= 来调节