java Long 的享元模式

先说下保护性拷贝

引用赋值,一般是老应用将其值赋给新引用,结果就是新、老应用指向堆中的同一个对象。而保护性拷贝,是将老引用指向的对象拷贝一份新的出来,结果是老引用指向老对象,新引用指向新对象,但新、老对象的内容一样。这种通过创建副本对象来避免共享的手段称之为【保护性拷贝(defensive copy)】。

享元模式

因为如果每次都保护性拷贝会创建大量的对象,占用内存。【享元模式】指的是当要创建的对象 obj1 的内容,与内存中已存在的对象 obj2 的内容相同时,直接将 obj2 拿来使用。这样就能大大减少对象的创建,提高消耗,降低开销。

Long 中的享元模式

这是 Long.java 源码,里面提供了 valueOf 方法创建对象。如果参数 l 的取值范围在 -128~127 之间,它是直接从 LongCache 中拿对象,超出这个范围时,才会 new Long()

public static Long valueOf(long l) {
    final int offset = 128;
    if (l >= -128 && l <= 127) { // will cache
        return LongCache.cache[(int)l + offset];
    }
    return new Long(l);
}

LongCache 做了什么呢?

private static class LongCache {
    private LongCache(){}

    // cache 数组存储 Long 对象。
    static final Long cache[] = new Long[-(-128) + 127 + 1];
	
    // 填充 ceche 数组。
    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Long(i - 128);
    }
}

当 jvm 第一次加载 LongCache 的 class 文件时做了三件事情:

  1. 创建数组 cache 并设定数组大小为 256。
  2. 执行静态代码块给静态数组 填充元素,将 -128~127 给填进去。
  3. 最后执行构造函数 LongCache()。

所以当我们调用 valueOf 的时时候,如果值在 -128~127,之间,其实是直接从 LongCache 中拿对象。

实际执行过程是怎么走的呢?

常写的代码

    Long num1 = 1L;
    Long num2 = 2L;

写法 1Long num1 = 1L 等价于 Long num1 = Long.valueOf(1L); 。为什么这么说呢?用了后者写法,IDEA 会提醒你简化。第二,Long.java 文件中总共有 4 个地方调用了 valueOf 方法,打个断点看一下。

执行 Long num1 = 1L:

  1. valueOf(1)
  2. 执行 LongCache.cache[1 + 128]
    1. 加载 LongCache 类文件;
    2. 创建 cache 数组,并设置数组大小;
    3. 执行静态代码块,填充数组;
    4. 执行构造方法。
  3. Long (1) 的引用赋值给 num1;

执行 Long num2 = 2L:

  1. valueOf(1)
  2. 执行 LongCache.cache[2 + 128]
  3. Long (2) 的引用赋值给 num2;

这里想想 Long mun3 = num1 + num2 跟第二句代码的执行过程是一样的。

都是在“拿”对象,而不是在 “创建”对象。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值