这一次,咱们来分析ImmutableSet,与ImmutableList大同小异,建议你们先看完上一篇Immutable Collections(2),在继续往下看html
相同:算法
不一样:数组
EmptyImmutableSet、SingletonImmutableSet不须要在作更多详细的说明,他们的存在的意义在于,对单个元素和空集合的操做优化,RegularImmutableSet的实现比较巧妙,它内部维护了两套数组,一套依照传入元素顺序,记录元素。另外一套根据Guava自定义的hash算法产生通过hash后的集合的位置,Guava的hash算法效率高于HashSet内部提供的hash算法,并且元素保证传入顺序。ide
private static <E> ImmutableSet<E> construct(int n, Object... elements) { //依然是根据元素个数的不一样,选择不一样的实现方式 switch (n) { case 0: return of(); case 1: @SuppressWarnings("unchecked") // safe; elements contains only E's E elem = (E) elements[0]; return of(elem); default: // continue below to handle the general case } int tableSize = chooseTableSize(n); Object[] table = new Object[tableSize]; int mask = tableSize - 1; int hashCode = 0; int uniques = 0; for (int i = 0; i < n; i++) { Object element = checkElementNotNull(elements[i], i); int hash = element.hashCode(); for (int j = Hashing.smear(hash); ; j++) { int index = j & mask; Object value = table[index]; if (value == null) { // Came to an empty slot. Put the element here. elements[uniques++] = element;//原有元素彻底不变的copy到elements集合中 table[index] = element;//table中存的是hash计算后的元素 hashCode += hash;//hash值 break; } else if (value.equals(element)) { break; } } } Arrays.fill(elements, uniques, n, null); if (uniques == 1) { // There is only one element or elements are all duplicates @SuppressWarnings("unchecked") // we are careful to only pass in E E element = (E) elements[0]; return new SingletonImmutableSet<E>(element, hashCode); //若是table的size和uniques差的不少,证实重复元素不少,须要从新计算table的size,避免空间浪费 } else if (tableSize != chooseTableSize(uniques)) { return construct(uniques, elements); } else { Object[] uniqueElements = (uniques < elements.length) ? ObjectArrays.arraysCopyOf(elements, uniques) : elements; return new RegularImmutableSet<E>(uniqueElements, hashCode, table, mask); } }
并且没必要担忧空间的浪费,其实两套数组内部,只是维护元素的引用。若是传入的元素集合存在大量的重复元素,ImmutableSet会copy后从新构造Set,以减小table数组(hash事后的)的空间浪费。详见代码。优化
那么,在RegularImmutableSet中,与set相关的O(1)操做,就会转为对table的操做,而对set的遍历等操做,会转为对elements数组的操做,代码以下:this
RegularImmutableSet( Object[] elements, int hashCode, Object[] table, int mask) { this.elements = elements;//维护原有集合顺序 this.table = table;//通过hash后的集合 this.mask = mask; this.hashCode = hashCode; } //contains操做,使用通过hash后的table @Override public boolean contains(Object target) { if (target == null) { return false; } for (int i = Hashing.smear(target.hashCode()); true; i++) { Object candidate = table[i & mask]; if (candidate == null) { return false; } if (candidate.equals(target)) { return true; } } } @Override public int size() { return elements.length;//size的实现确定使用elements,由于table在有少许重复元素的状况下,稍大于elements }