Java源码分析:Guava之不可变集合ImmutableMap的源码分析 (2)

image

ImmutableMapEntry<K, V>顶部同样是实现了Entry<K,V>——

image

可见,ImmutableMap与HashMap一样,其存储key-value的对象所属的类,都直接或者间接地实现了Entry<K,V>接口。

分析到这里,再看回Builder<K, V>类源码,就很容易明白 ,这个ImmutableMapEntry<K, V>[] entries与HashMap的数组类似,都是用来存储key-value的数据。

接下来,就是分析put的逻辑原理了。

前面分析到的Builder类,其实是属于抽象类 ImmutableMap<K, V>中的内部静态类,这就意味着,执行ImmutableMap.<String, String>builder().put("Monday","今天上英语课")的本质,其实是相当于执行了ImmutableMap.new Builder<K, V>().put("Monday","今天上英语课")。

put方法的源码如下:

public Builder<K, V> put(K key, V value) { ensureCapacity(size + 1); ImmutableMapEntry<K, V> entry = entryOf(key, value); // don't inline this: we want to fail atomically if key or value is null entries[size++] = entry; return this; }

一、先看第一行代码调用的方法,其作用是判断当新增一个key-value对象存到数组时,是否会有溢出的可能,若出现溢出的情况,就先对数组进行扩容。

private void ensureCapacity(int minCapacity) { if (minCapacity > entries.length) { entries = Arrays.copyOf( entries, ImmutableCollection.Builder.expandedCapacity(entries.length, minCapacity)); entriesUsed = false; } }

二、第二行ImmutableMapEntry<K, V> entry = entryOf(key, value)就是创建一个新的ImmutableMapEntry对象,通过构造器初始化赋值给对象的key与value——

static <K, V> ImmutableMapEntry<K, V> entryOf(K key, V value) { return new ImmutableMapEntry<K, V>(key, value); }

三、第三行代码 entries[size++] = entry是将新增的ImmutableMapEntry对象存储到数组空闲的位置上,这样通过put(key,value)缓存进来的key-value值,就通过对象的形式存入到了数组当中。

四、最后一行,是返回一个this,ImmutableMap能实现链式编程的原因,就是在这个this上。

当理解了这个this,就会理解ImmutableMap设计的精妙之处。

当我们使用链式编程ImmutableMap.<String, String>builder().put("key1","value1").put("key2","value2") .put("key2","value3")来赋值时,其内部就是反复调用了内部静态类Builder当中的put()方法,那么问题来了,为什么能反复调用呢?

答案就是这个返回的this,其返回的还是Builder对象本身啊,Builderd对象当然可以继续调用其put方法了。在这个反复调用的过程中, 只有entries[size++] 是一直在新增变化的。

这其实是建造者设计模式的一种体现,只不过平常遇到的建造者设计模式,大多都是将对象的各个属性灵活进行拼装,组成一个定制化的对象,而这里,则是灵活去定制化一个数组存储情况。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydsxx.html