Guava源码解析十二:Multiset源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dancheng1/article/details/85256804

对于Multiset集合可以存储重复的值,他的强大之处是他的同一个值个数统计功能。实现类为HashMulitset类,他的继承关系图为:

从Multiset接口开始分析源码:

public interface Multiset<E> extends Collection<E> {
    //返回给定参数元素的个数
    int count(@Nullable Object var1);
	//向其中添加指定个数的元素
    int add(@Nullable E var1, int var2);
	//移除相应个数的元素
    int remove(@Nullable Object var1, int var2);
	//设定某一个元素的重复次数
    int setCount(E var1, int var2);
	//将符合原有重复个数的元素修改为新的重复次数
    boolean setCount(E var1, int var2, int var3);
	//将不同的元素放入一个Set中
    Set<E> elementSet();
    //类似与Map.entrySet 返回Set<Multiset.Entry>。包含的Entry支持使用getElement()和getCount()
    Set<Multiset.Entry<E>> entrySet();
    boolean equals(@Nullable Object var1);
    int hashCode();
    String toString();
	//返回迭代器
    Iterator<E> iterator();
	//判断是否存在某个元素
    boolean contains(@Nullable Object var1);
	//判断是否存在集合中所有元素
    boolean containsAll(Collection<?> var1);
	//添加元素
    boolean add(E var1);
	//删除某个元素
    boolean remove(@Nullable Object var1);
	//删除集合中所有元素
    boolean removeAll(Collection<?> var1);
    boolean retainAll(Collection<?> var1);
    public interface Entry<E> {
        E getElement();
        int getCount();
        boolean equals(Object var1);
        int hashCode();
        String toString();
    }
}

对于Multiset的接口中方法的实现在AbstractMapBasedMultiset抽象类中,下面针对AbstractMapBasedMultiset类的存储数据结构。add、remove、count和迭代器的实现进行分析

存储数据结构

private transient Map<E, Count> backingMap;
可以看到他的实际存储结构为一个Map,key为存储元素,Count类型存储是key这个元素的个数,看一下Count源码:
final class Count implements Serializable {
    //记录当前个数
    private int value;
    //构造方法,为变量赋值
    Count(int value) {
        this.value = value;
    }
   	//获取当前个数
    public int get() {
        return this.value;
    }
    //加上指定个数,先加在返回加完后的值
    public int getAndAdd(int delta) {
        int result = this.value;
        this.value = result + delta;
        return result;
    }
    //加上指定个数,先返回,在进行想加
    public int addAndGet(int delta) {
        return this.value += delta;
    }
    //直接设置当前个数
    public void set(int newValue) {
        this.value = newValue;
    }
    //先设置新的值在返回这个值大小
    public int getAndSet(int newValue) {
        int result = this.value;
        this.value = newValue;
        return result;
    }
    public int hashCode() {
        return this.value;
    }
    public boolean equals(@Nullable Object obj) {
        return obj instanceof Count && ((Count)obj).value == this.value;
    }
    public String toString() {
        return Integer.toString(this.value);
    }
}

构造方法

protected AbstractMapBasedMultiset(Map<E, Count> backingMap) {
    //存储的Map可以为任意类型的Map
    this.backingMap = (Map)Preconditions.checkNotNull(backingMap);
    //获取当前Multiset长度
    this.size = (long)super.size();
}

add方法

public int add(@Nullable E element, int occurrences) {
    //如果想要添加的个数为0
    if(occurrences == 0) {
        //如果存在则返回这个元素的个数,否则返回0
        return this.count(element);
    } else {
        Preconditions.checkArgument(occurrences > 0, "occurrences cannot be negative: %s", new Object[]{Integer.valueOf(occurrences)});
        //根据想要插入的元素在map中找到Count
        Count frequency = (Count)this.backingMap.get(element);
        int oldCount;
        //如果key所对应的Count为null
        if(frequency == null) {
            //设置原来数据为0
            oldCount = 0;
            //将这个元素和所对应的Count添加到Map中
            this.backingMap.put(element, new Count(occurrences));
        } else {
            //获取原来个数
            oldCount = frequency.get();
            //计算出新的个数
            long newCount = (long)oldCount + (long)occurrences;
            Preconditions.checkArgument(newCount <= 2147483647L, "too many occurrences: %s", new Object[]{Long.valueOf(newCount)});
            //为key所对应的Count添加occurrences个
            frequency.getAndAdd(occurrences);
        }
        //将当前的size加上occurrences
        this.size += (long)occurrences;
        //返回原来数据
        return oldCount;
    }
}

remove方法

public int remove(@Nullable Object element, int occurrences) {
    //如果想要删除0个
    if(occurrences == 0) {
        //返回当前这个元素的个数,如果不存在容器中返回0
        return this.count(element);
    } else {
        Preconditions.checkArgument(occurrences > 0, "occurrences cannot be negative: %s", new Object[]{Integer.valueOf(occurrences)});
        //根据要删除的值作为key获取到他的Count
        Count frequency = (Count)this.backingMap.get(element);
        //如果对应的Count为null,则返回0
        if(frequency == null) {
            return 0;
        } else {
            //获取当前个数
            int oldCount = frequency.get();
            int numberRemoved;
            //如果原来个数大于想要删除的个数
            if(oldCount > occurrences) {
                numberRemoved = occurrences;
            } else {
                //如果原来个数小于想要删除的个数
                numberRemoved = oldCount;
                //直接将这个元素在Map中删除
                this.backingMap.remove(element);
            }
            //设置这个元素对应的Count
            frequency.addAndGet(-numberRemoved);
            this.size -= (long)numberRemoved;
            return oldCount;
        }
    }
}

count方法

public int count(@Nullable Object element) {
    //以传入的作为key,在map容器中找到相对应的Count
    Count frequency = (Count)Maps.safeGet(this.backingMap, element);
    //如果这个Count为空,则返回0,否则返回Count中的值
    return frequency == null?0:frequency.get();
}

迭代器

public Iterator<E> iterator() {
    return new AbstractMapBasedMultiset.MapBasedMultisetIterator();
}

可以看到Multiset中有一个实现了Iterator接口的类:

private class MapBasedMultisetIterator implements Iterator<E> {
    final Iterator<java.util.Map.Entry<E, Count>> entryIterator;
    java.util.Map.Entry<E, Count> currentEntry;
    int occurrencesLeft;
    boolean canRemove;
    MapBasedMultisetIterator() {
        //获取当前map容器的迭代器
        this.entryIterator = AbstractMapBasedMultiset.this.backingMap.entrySet().iterator();
    }
    //根据当前迭代器判断是否还有元素
    public boolean hasNext() {
        return this.occurrencesLeft > 0 || this.entryIterator.hasNext();
    }
    public E next() {
        //如果occurrencesLeft为0,则说明现在处于刚开始,或上一个元素完成
        if(this.occurrencesLeft == 0) {
            //迭代器向下获取一个元素
            this.currentEntry = (java.util.Map.Entry)this.entryIterator.next();
            //获取到当前元素的个数
            this.occurrencesLeft = ((Count)this.currentEntry.getValue()).get();
        }
        //因为是获取一个元素,所以减去这一个
        --this.occurrencesLeft;
        this.canRemove = true;
        return this.currentEntry.getKey();
    }
    public void remove() {
        CollectPreconditions.checkRemove(this.canRemove);
        int frequency = ((Count)this.currentEntry.getValue()).get();
        if(frequency <= 0) {
            throw new ConcurrentModificationException();
        } else {
            if(((Count)this.currentEntry.getValue()).addAndGet(-1) == 0) {
                this.entryIterator.remove();
            }

            AbstractMapBasedMultiset.access$110(AbstractMapBasedMultiset.this);
            this.canRemove = false;
        }
    }
}

这个迭代器的好处是,存储多个相同的值,不会占用多个地方,只会占用1个位置。

猜你喜欢

转载自blog.csdn.net/dancheng1/article/details/85256804
今日推荐