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;
}

Guava BiMap AbstractBiMap的更多相关文章

  1. Guava BiMap

    BiMap主要的就是用于key,value的互相映射,获取相互的结果,还保证值value是唯一的,key相同覆盖原来值. 举例: BiMap<Integer, String> empIDN ...

  2. 【Java必修课】通过Value获取Map中的键值Key的四种方法

    1 简介 我们都知道Map是存放键值对<Key,Value>的容器,知道了Key值,使用方法Map.get(key)能快速获取Value值.然而,有的时候我们需要反过来获取,知道Value ...

  3. 通过Value获取Map中的键值Key的四种方法

    1 简介 我们都知道Map是存放键值对<Key,Value>的容器,知道了Key值,使用方法Map.get(key)能快速获取Value值.然而,有的时候我们需要反过来获取,知道Value ...

  4. Guava学习笔记:Guava新增集合类型-Bimap

    BiMap提供了一种新的集合类型,它提供了key和value的双向关联的数据结构. 通常情况下,我们在使用Java的Map时,往往是通过key来查找value的,但是如果出现下面一种场景的情况,我们就 ...

  5. Guava集合-BiMap

    在本篇文章中我们将介绍Guava集合中的BiMap这个接口. com.google.common.collect Interface BiMap<K,V> BiMap接口的父接口是Map& ...

  6. Guava新增集合类型-Bimap

    Guava新增集合类型-Bimap BiMap提供了一种新的集合类型,它提供了key和value的双向关联的数据结构. 通常情况下,我们在使用Java的Map时,往往是通过key来查找value的,但 ...

  7. java代码之美(7)---guava之Bimap

    guava之Bimap bimap的作用很清晰:它是一个一一映射,可以通过key得到value,也可以通过value得到key. 一.概述 1.bimap和普通HashMap区别 (1)在Java集合 ...

  8. guava学习:guava集合类型-Bimap

    学习guava让我惊喜的第二个接口就是:Bimap BiMap是一种特殊的映射其保持映射,同时确保没有重复的值是存在于该映射和一个值可以安全地用于获取键背面的倒数映射. 最近开发过程中,经常会有这种根 ...

  9. Guava包学习---Bimap

    Bimap也是Guava中提供的新集合类,别名叫做双向map,就是key->value,value->key,也就是你可以通过key定位value,也可以用value定位key. 这个场景 ...

随机推荐

  1. POJ 3017 Cut the Sequence

    [题目链接] $O(n^2)$ 效率的 dp 递推式:${ dp }_{ i }=min\left( dp_{ j }+\overset { i }{ \underset { x=j+1 }{ max ...

  2. 洛谷P3398 仓鼠找sugar [LCA]

    题目传送门 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而 ...

  3. Pwn入坑指南

    栈溢出原理 参考我之前发的一篇 Windows栈溢出原理 还有 brant 师傅的<0day安全笔记> Pwn常用工具 gdb:Linux下程序调试 PEDA:针对gdb的python漏洞 ...

  4. Linux学习路线+资源

    Linux学习路线,个人收集分享 学习路线图 资源链接(蓝色下划线字体对应相应资源链接) Linux 基础 Linux 基础 Linux安装专题教程 Linux中文环境 Linux—从菜鸟到高手 鸟哥 ...

  5. 一个关于react-native的demo,详细请转GitHub

    react native 0 介绍 支持ios和android两个平台 下载:git clone https://github.com/chunlei36/react-native-full-exam ...

  6. qq sid qq sid 是什么 qq sid 怎么用

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha ======= qq sid qq sid  是什么 qq sid  怎么用 ===== ...

  7. HDU 3802Ipad,IPhone

    前两块可以看成是不是二次剩余,快速幂计算即可. 后半部分可以看成x1=a+b+2ab,x2=a+b-2ab为特征方程x^2-px-qx=0的两根 然后可以通过韦达定理求出p和q,因此递推式为A(n+2 ...

  8. Codeforces.566F.Clique in the Divisibility Graph(DP)

    题目链接 \(Description\) 给定集合\(S=\{a_1,a_2,\ldots,a_n\}\),集合中两点之间有边当且仅当\(a_i|a_j\)或\(a_j|a_i\). 求\(S\)最大 ...

  9. BZOJ.1014.[JSOI2008]火星人(Splay 二分 Hash)

    题目链接 后缀数组显然不行啊.求LCP还可以哈希+二分,于是考虑用平衡树维护哈希值. \[某一节点的哈希值 = hs[lson]*base^{sz[rson]+1} + s[rt]*base^{sz[ ...

  10. mount: unknown filesystem type 'vboxsf' centos ubuntu 处理方案

    Vagrant was unable to mount VirtualBox shared folders. This is usually because the filesystem " ...