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

最新文章

  1. Android笔记:多线程
  2. RequireJS 快速入门
  3. SQLServer idenity 字段跳值
  4. Routine Problem(数学)
  5. jar包双击执行程序
  6. 走进科学之WAF(Web Appllication Firewall)篇
  7. wire与reg的区别?转载大神!
  8. 关于搭建haddoop分布式系统的全部过程复习
  9. AOP Concepts
  10. Arduino live weather broadcasting 实时天气站
  11. asp 301代码
  12. Vue声明式渲染
  13. ArcGIS Engine 笔记-控件类型
  14. linux定时备份学习笔记
  15. Kong(V1.0.2)loadbalancing
  16. Java判断不为空的工具类总结
  17. Lerning Entity Framework 6 ------ Working with in-memory data
  18. 【转】进程同步之信号量机制(pv操作)及三个经典同步问题
  19. java高级精讲之高并发抢红包~揭开Redis分布式集群与Lua神秘面纱
  20. selenium+Page Objects(第二话)

热门文章

  1. 2015 ACM Amman Collegiate Programming Contest 题解
  2. P3402 最长公共子序列
  3. 001.DNS原理及配置格式
  4. Gift动图分解小工具
  5. js原型鏈與js繼承解析
  6. BZOJ 4706: B君的多边形 找规律
  7. Kernel 4.9的BBR拥塞控制算法与锐速
  8. Linux学习笔记04—IP配置
  9. 使用Sublime text 3打造一个小巧但强大的Go语言开发IDE
  10. mui选择器和dom获取元素的区别(记得把mui对象转为dom对象才能调用用dom方法)