Flyweight
定义
共享存储单元,节约内存空间。
使用场景
例如文本编辑器里,每个字符都有字体大小,显示颜色,背景颜色等属性。将这些属性抽取为字体,每个字体的属性在内存中只保留一份即可。感觉和CSS挺像的,不过享元模式侧重点不是代码复用,而是对象复用。
JDK里使用的地方
Integer缓存
int类型在自动装箱时,调用java.lang.Integer#valueOf(int)
public static Integer valueOf(int i) {
// 如果在缓存范围内
if (i >= IntegerCache.low && i <= IntegerCache.high)
// 直接返回缓存中的对象
return IntegerCache.cache[i (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache是Integer的私有静态内部类
代码语言:javascript复制 private static class IntegerCache {
// 缓存范围低位是固定的
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// 高位默认127,可配置
// high value may be configured by property
int h = 127;
// 读取JVM参数
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// 解析配置的参数为数字失败时,没有任何提示
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) 1];
int j = low;
// 第一次调用java.lang.Integer#valueOf(int)时才初始化,实例化缓存范围内的所有对象,和String的缓存机制不同
for(int k = 0; k < cache.length; k )
cache[k] = new Integer(j );
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
String缓存
通过字面量的形式创建字符串时,jvm会先在字符串常量池中查找是否有相同内容的字符串,如果要,就返回其引用。否则就创建字符串对象,并存入字符串常量池里。
字符串常量池的位置
在JDK 7以前的版本中,字符串常量池是放在永久代中的。 因为按照计划,JDK会在后续的版本中通过元空间来代替永久代,所以首先在JDK 7中,将字符串常量池先从永久代中移出,暂时放到了堆内存中。 在JDK 8中,彻底移除了永久代,使用元空间替代了永久代,于是字符串常量池再次从堆内存移动到永久代(元空间)