十、享元模式

2022-09-21 10:00:42 浏览数 (1)

Flyweight

定义

共享存储单元,节约内存空间。

使用场景

例如文本编辑器里,每个字符都有字体大小,显示颜色,背景颜色等属性。将这些属性抽取为字体,每个字体的属性在内存中只保留一份即可。感觉和CSS挺像的,不过享元模式侧重点不是代码复用,而是对象复用。

JDK里使用的地方

Integer缓存

int类型在自动装箱时,调用java.lang.Integer#valueOf(int)

代码语言:javascript复制
    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中,彻底移除了永久代,使用元空间替代了永久代,于是字符串常量池再次从堆内存移动到永久代(元空间)

0 人点赞