BiMap

BiMap是一个结构,他定义了一个Map结构,代表这个Map的key和value都具有唯一性, 并且可以生成相互联系的反向视图, 反向视图的数据会随着本体BiMap的变更而变更

/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import com.google.common.annotations.GwtCompatible;

import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

/**
 * A bimap (or "bidirectional map") is a map that preserves the uniqueness of
 * its values as well as that of its keys. This constraint enables bimaps to
 * support an "inverse view", which is another bimap containing the same entries
 * as this bimap but with reversed keys and values.
 *
 * bimap (或者叫做 "bidirectional map") 是指一个map同时保证了values和keys的唯一性.
 * 这种约束允许bimap支持逆视图, 也就是另一个bimap和它拥有相同的entry, 但是这些entry的value和key对换
 *
 * <p>See the Guava User Guide article on <a href=
 * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
 * {@code BiMap}</a>.
 *
 * @author Kevin Bourrillion
 * @since 2.0 (imported from Google Collections Library)
 */
@GwtCompatible
public interface BiMap<K, V> extends Map<K, V> {
    // Modification Operations

    /**
     * {@inheritDoc}
     *
     * @throws IllegalArgumentException if the given value is already bound to a
     *     different key in this bimap. The bimap will remain unmodified in this
     *     event. To avoid this exception, call {@link #forcePut} instead.
     *
     * 如果给定的value已经存在不同的key中则会抛出IllegalArgumentException.在这种情况下
     * bimap会保持不变你可以调用 forcePut 来避免这个exception
     */
    @Override
    V put(@Nullable K key, @Nullable V value);

    /**
     * An alternate form of {@code put} that silently removes any existing entry
     * with the value {@code value} before proceeding with the {@link #put}
     * operation. If the bimap previously contained the provided key-value
     * mapping, this method has no effect.
     *
     * put 的替代方法, 在put之前他会强制移除和你想插入的value一样的entry.如果bimap已经包含了提供的
     * key-value映射, 那么这个方法无效.
     *
     * <p>Note that a successful call to this method could cause the size of the
     * bimap to increase by one, stay the same, or even decrease by one.
     *
     * 注意对这个方法成功的调用会导致一个bimap的size +1, 不变, 甚至-1 (当bimap里存在(k1, v1)
     * (k2, v2))而你打算forcePut(k1, v2),那么 (k1, v1) (k2, v2) 都会被删除
     *
     * <p><b>Warning:</b> If an existing entry with this value is removed, the key
     * for that entry is discarded and not returned.
     *
     * 警告: 加入一个指定value已经存在的entry被删除,那么这个entry的key会被丢弃且不会被返回
     *
     * @param key the key with which the specified value is to be associated
     * @param value the value to be associated with the specified key
     * @return the value which was previously associated with the key, which may
     *     be {@code null}, or {@code null} if there was no previous entry
     *
     *     返回原来和这个key关联的value, 如果原来这个key对应的entry不存在则返回null
     */
    V forcePut(@Nullable K key, @Nullable V value);

    // Bulk Operations
    // 扩容操作

    /**
     * {@inheritDoc}
     *
     * <p><b>Warning:</b> the results of calling this method may vary depending on
     * the iteration order of {@code map}.
     *
     * 警告: 这个方法的调用结果可能非常依赖于map的遍历顺序
     *
     * @throws IllegalArgumentException if an attempt to {@code put} any
     *     entry fails. Note that some map entries may have been added to the
     *     bimap before the exception was thrown.
     *     任何put操作失败都会抛出一个IllegalArgumentException. 注意有些map entry可能
     *     在异常抛出之前已经被加到bimap里了
     */
    @Override
    void putAll(Map<? extends K, ? extends V> map);

    // Views

    /**
     * {@inheritDoc}
     *
     * <p>Because a bimap has unique values, this method returns a {@link Set},
     * instead of the {@link java.util.Collection} specified in the {@link Map}
     * interface.
     *
     * 由于一个bimap的value具有唯一性,这个方法返回一个set而不是返回一个由map接口指定的collection
     */
    @Override
    Set<V> values();

    /**
     * Returns the inverse view of this bimap, which maps each of this bimap's
     * values to its associated key. The two bimaps are backed by the same data;
     * any changes to one will appear in the other.
     *
     * 返回一个bimap的反序视图 -- 一个将原来的bimap的value映射到key的map, 这两个bimaps有相同
     * 的数据组成. 任何对其中一个的修改将会导致另一个的修改
     *
     * <p><b>Note:</b>There is no guaranteed correspondence between the iteration
     * order of a bimap and that of its inverse.
     *
     *提示: bimap的和它的反序视图之间的遍历顺序是没有保证的
     *
     * @return the inverse view of this bimap
     * 返回bimap的反序视图
     */
    BiMap<V, K> inverse();
}

 

AbstractBiMap

AbstractBiMap实现了BiMap接口, 把BiMap的方法实现了一遍. 其中最主要的原理是使用forward和backward来表示两个kv相互对调的Map来构造AbstractBiMap,然后AbstractBiMap内部用

    private transient Map<K, V> delegate;
    transient AbstractBiMap<V, K> inverse;

delegate表示的正向的Map, inverse表示的反向Map, 他们的关系就像是一个相互死循环,代码分析如下

/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Objects;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

/**
 * A general-purpose bimap implementation using any two backing {@code Map}
 * instances.
 *
 * 一个由任意两个Map实例支持的通用bimap
 *
 * <p>Note that this class contains {@code equals()} calls that keep it from
 * supporting {@code IdentityHashMap} backing maps.
 *
 * @author Kevin Bourrillion
 * @author Mike Bostock
 */
@GwtCompatible(emulated = true)
abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
        implements BiMap<K, V>, Serializable {

    private transient Map<K, V> delegate;
    transient AbstractBiMap<V, K> inverse;

    /** Package-private constructor for creating a map-backed bimap. */
    /** 用来创建一个map-backed的bimap包私有构造器 */
    AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
        setDelegates(forward, backward);
    }

    /** Private constructor for inverse bimap. */
    /** 用来生成bimap反向视图的私有构造器 */
    private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
        delegate = backward;
        inverse = forward;
    }

    @Override protected Map<K, V> delegate() {
        return delegate;
    }

    /**
     * Returns its input, or throws an exception if this is not a valid key.
     * 返回输入参数,如果key不合法则抛出一个异常
     */
    K checkKey(@Nullable K key) {
        return key;
    }

    /**
     * Returns its input, or throws an exception if this is not a valid value.
     * 返回输入参数,如果value不合法则抛出一个异常
     */
    V checkValue(@Nullable V value) {
        return value;
    }

    /**
     * Specifies the delegate maps going in each direction. Called by the
     * constructor and by subclasses during deserialization.
     *
     * 指定各个方向的代理map. 由构造器和子类在反序列化时调用
     */
    void setDelegates(Map<K, V> forward, Map<V, K> backward) {
        checkState(delegate == null);
        checkState(inverse == null);
        checkArgument(forward.isEmpty());
        checkArgument(backward.isEmpty());
        checkArgument(forward != backward);
        delegate = forward;
        inverse = new Inverse<V, K>(backward, this);
    }

    void setInverse(AbstractBiMap<V, K> inverse) {
        this.inverse = inverse;
    }

    // Query Operations (optimizations)
    // 查询操作(优化)

    @Override public boolean containsValue(Object value) {
        return inverse.containsKey(value);
    }

    // Modification Operations
    // 修改操作

    @Override public V put(K key, V value) {
        return putInBothMaps(key, value, false);
    }

    @Override
    public V forcePut(K key, V value) {
        return putInBothMaps(key, value, true);
    }

    /**
     * 同时在delegate和inverse中插入key和value
     *
     * @param key
     * @param value
     * @param force
     * @return
     */
    private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
        checkKey(key);
        checkValue(value);
        boolean containedKey = containsKey(key);
        // entry 已存在,直接返回value
        if (containedKey && Objects.equal(value, get(key))) {
            return value;
        }
        if (force) {
            // 强制put key & value
            inverse().remove(value);
        } else {
            // 否则检查value是否存在,存在则抛出异常
            checkArgument(!containsValue(value), "value already present: %s", value);
        }
        V oldValue = delegate.put(key, value);
        // 更新反向视图
        updateInverseMap(key, containedKey, oldValue, value);
        return oldValue;
    }

    /**
     * 更新反向视图
     */
    private void updateInverseMap(
            K key, boolean containedKey, V oldValue, V newValue) {
        // key存在(相对于inverse来说应该是value存在),先删除旧的entry
        if (containedKey) {
            removeFromInverseMap(oldValue);
        }
        inverse.delegate.put(newValue, key);
    }

    @Override public V remove(Object key) {
        return containsKey(key) ? removeFromBothMaps(key) : null;
    }

    private V removeFromBothMaps(Object key) {
        V oldValue = delegate.remove(key);
        removeFromInverseMap(oldValue);
        return oldValue;
    }

    private void removeFromInverseMap(V oldValue) {
        inverse.delegate.remove(oldValue);
    }

    // Bulk Operations
    // 扩容操作

    @Override public void putAll(Map<? extends K, ? extends V> map) {
        for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    @Override public void clear() {
        delegate.clear();
        inverse.delegate.clear();
    }

    // Views
    // 视图

    @Override
    public BiMap<V, K> inverse() {
        return inverse;
    }

    private transient Set<K> keySet;

    @Override public Set<K> keySet() {
        Set<K> result = keySet;
        return (result == null) ? keySet = new KeySet() : result;
    }

    private class KeySet extends ForwardingSet<K> {
        @Override protected Set<K> delegate() {
            return delegate.keySet();
        }

        @Override public void clear() {
            AbstractBiMap.this.clear();
        }

        @Override public boolean remove(Object key) {
            if (!contains(key)) {
                return false;
            }
            removeFromBothMaps(key);
            return true;
        }

        @Override public boolean removeAll(Collection<?> keysToRemove) {
            return standardRemoveAll(keysToRemove);
        }

        @Override public boolean retainAll(Collection<?> keysToRetain) {
            return standardRetainAll(keysToRetain);
        }

        @Override public Iterator<K> iterator() {
            return Maps.keyIterator(entrySet().iterator());
        }
    }

    private transient Set<V> valueSet;

    @Override public Set<V> values() {
    /*
     * We can almost reuse the inverse's keySet, except we have to fix the
     * iteration order so that it is consistent with the forward map.
     *
     * 我们可以重用inverse的keyset来得到forward的valueset, 除非我们关注遍历器的顺序,
     * 那样可以考虑使用forward map
     */
        Set<V> result = valueSet;
        return (result == null) ? valueSet = new ValueSet() : result;
    }

    private class ValueSet extends ForwardingSet<V> {
        /** 使用inverse的keySet来获取valueSet */
        final Set<V> valuesDelegate = inverse.keySet();

        @Override protected Set<V> delegate() {
            return valuesDelegate;
        }

        @Override public Iterator<V> iterator() {
            return Maps.valueIterator(entrySet().iterator());
        }

        @Override public Object[] toArray() {
            return standardToArray();
        }

        @Override public <T> T[] toArray(T[] array) {
            return standardToArray(array);
        }

        @Override public String toString() {
            return standardToString();
        }
    }

    private transient Set<Entry<K, V>> entrySet;

    @Override public Set<Entry<K, V>> entrySet() {
        Set<Entry<K, V>> result = entrySet;
        return (result == null) ? entrySet = new EntrySet() : result;
    }

    private class EntrySet extends ForwardingSet<Entry<K, V>> {
        final Set<Entry<K, V>> esDelegate = delegate.entrySet();

        @Override protected Set<Entry<K, V>> delegate() {
            return esDelegate;
        }

        @Override public void clear() {
            AbstractBiMap.this.clear();
        }

        @Override public boolean remove(Object object) {
            if (!esDelegate.contains(object)) {
                return false;
            }

            // safe because esDelgate.contains(object).
            Entry<?, ?> entry = (Entry<?, ?>) object;
            inverse.delegate.remove(entry.getValue());
      /*
       * Remove the mapping in inverse before removing from esDelegate because
       * if entry is part of esDelegate, entry might be invalidated after the
       * mapping is removed from esDelegate.
       *
       * 删除forward的entry之前先将inverse的entry删除,因为如果entry是forward的一部分,
       * 那么entry可能会在forward中删除以后变成不可用
       */
            esDelegate.remove(entry);
            return true;
        }

        @Override public Iterator<Entry<K, V>> iterator() {
            final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
            return new Iterator<Entry<K, V>>() {
                Entry<K, V> entry;

                @Override public boolean hasNext() {
                    return iterator.hasNext();
                }

                @Override public Entry<K, V> next() {
                    entry = iterator.next();
                    final Entry<K, V> finalEntry = entry;

                    return new ForwardingMapEntry<K, V>() {
                        @Override protected Entry<K, V> delegate() {
                            return finalEntry;
                        }

                        @Override public V setValue(V value) {
                            // Preconditions keep the map and inverse consistent.
                            checkState(contains(this), "entry no longer in map");
                            // similar to putInBothMaps, but set via entry
                            if (Objects.equal(value, getValue())) {
                                return value;
                            }
                            checkArgument(!containsValue(value),
                                    "value already present: %s", value);
                            V oldValue = finalEntry.setValue(value);
                            checkState(Objects.equal(value, get(getKey())),
                                    "entry no longer in map");
                            updateInverseMap(getKey(), true, oldValue, value);
                            return oldValue;
                        }
                    };
                }

                @Override public void remove() {
                    checkState(entry != null);
                    V value = entry.getValue();
                    iterator.remove();
                    removeFromInverseMap(value);
                }
            };
        }

        // See java.util.Collections.CheckedEntrySet for details on attacks.

        @Override public Object[] toArray() {
            return standardToArray();
        }
        @Override public <T> T[] toArray(T[] array) {
            return standardToArray(array);
        }
        @Override public boolean contains(Object o) {
            return Maps.containsEntryImpl(delegate(), o);
        }
        @Override public boolean containsAll(Collection<?> c) {
            return standardContainsAll(c);
        }
        @Override public boolean removeAll(Collection<?> c) {
            return standardRemoveAll(c);
        }
        @Override public boolean retainAll(Collection<?> c) {
            return standardRetainAll(c);
        }
    }

    /** The inverse of any other {@code AbstractBiMap} subclass. */
    /** inverse类, 实际上实现很简单,就是把AbstractBiMap的forward和inverse给反过来了 */
    private static class Inverse<K, V> extends AbstractBiMap<K, V> {
        private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
            super(backward, forward);
        }

    /*
     * Serialization stores the forward bimap, the inverse of this inverse.
     * Deserialization calls inverse() on the forward bimap and returns that
     * inverse.
     *
     * 序列化储存forward bimap, inverse的反向.
     * 反序列化调用forward的inverse()并返回这个inverse
     *
     * If a bimap and its inverse are serialized together, the deserialized
     * instances have inverse() methods that return the other.
     */

        @Override
        K checkKey(K key) {
            return inverse.checkValue(key);
        }

        @Override
        V checkValue(V value) {
            return inverse.checkKey(value);
        }

        /**
         * @serialData the forward bimap
         *
         * 由于 delegate和inverse都有transient关键字
         * 所以序列化方法只会序列化inverse()的内容
         */
        @GwtIncompatible("java.io.ObjectOuputStream")
        private void writeObject(ObjectOutputStream stream) throws IOException {
            stream.defaultWriteObject();
            stream.writeObject(inverse());
        }

        /**
         * 反序列化恢复inverse
         */
        @GwtIncompatible("java.io.ObjectInputStream")
        @SuppressWarnings("unchecked") // reading data stored by writeObject
        private void readObject(ObjectInputStream stream)
                throws IOException, ClassNotFoundException {
            stream.defaultReadObject();
            setInverse((AbstractBiMap<V, K>) stream.readObject());
        }

        /**
         * 最后反序列化返回的是inverse().inverse(),其实就是forward了.
         */
        @GwtIncompatible("Not needed in the emulated source.")
        Object readResolve() {
            return inverse().inverse();
        }

        @GwtIncompatible("Not needed in emulated source.")
        private static final long serialVersionUID = 0;
    }

    @GwtIncompatible("Not needed in emulated source.")
    private static final long serialVersionUID = 0;
}

 

posted on 2013-09-25 19:36  ZimZz  阅读(1236)  评论(0编辑  收藏  举报