阅读(4547) (0)

鸿蒙OS IdentityHashMap

2022-06-16 16:24:51 更新

IdentityHashMap

java.lang.Object

|---java.util.AbstractMap<K,V&

|---|---java.util.IdentityHashMap<K,V&

public class IdentityHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Serializable, Cloneable

此类使用哈希表实现 Map 接口,在比较键(和值)时使用引用相等代替对象相等。 换句话说,在 IdentityHashMap 中,当且仅当 (k1==k2) 时,两个键 k1 和 k2 才被认为相等。 (在正常的 Map 实现(如 HashMap)中,当且仅当 (k1==null ? k2==null : k1.equals(k2)) 时,才认为两个键 k1 和 k2 相等。)

这个类不是一个通用的 Map 实现! 虽然这个类实现了 Map 接口,但它故意违反了 Map 的一般合同,该合同要求在比较对象时使用 equals 方法。 此类仅在需要引用相等语义的极少数情况下使用。

此类的典型用途是保留拓扑的对象图转换,例如序列化或深度复制。 要执行这样的转换,程序必须维护一个“节点表”来跟踪所有已处理的对象引用。 节点表不能等同于不同的对象,即使它们碰巧相等。 此类的另一个典型用途是维护代理对象。 例如,调试工具可能希望为被调试程序中的每个对象维护一个代理对象。

此类提供所有可选的映射操作,并允许空值和空键。 此类不保证 map 的顺序; 特别是,它不保证订单会随着时间的推移保持不变。

此类为基本操作(get 和 put)提供恒定时间性能,假设系统身份哈希函数 (System#identityHashCode(Object)) 将元素正确地分散在桶中。

此类有一个调整参数(影响性能但不影响语义):预期的最大大小。此参数是映射预计持有的键值映射的最大数量。在内部,此参数用于确定最初包含哈希表的桶数。未指定预期的最大大小和桶数之间的精确关系。

如果映射的大小(键值映射的数量)充分超过预期的最大大小,则增加桶的数量。增加桶的数量(“重新散列”)可能相当昂贵,因此创建具有足够大的预期最大大小的身份散列映射是值得的。另一方面,对集合视图的迭代需要的时间与哈希表中的桶数成正比,因此如果您特别关心迭代性能或内存使用情况,则不要将预期的最大大小设置得太高。

请注意,此实现不同步。如果多个线程同时访问一个身份哈希图,并且至少有一个线程在结构上修改了该 map,则必须在外部进行同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改。)这通常通过在自然封装映射的某个对象上同步来完成.如果不存在这样的对象,则应使用 Collections#synchronizedMap 方法 “wrapped” map。这最好在创建时完成,以防止对地图的意外不同步访问:

   Map m = Collections.synchronizedMap(new IdentityHashMap(...));

由此类的所有“集合视图方法”返回的集合的迭代器方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对映射进行结构修改,除了通过迭代器自己的删除之外的任何方式方法,迭代器将抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖于这个异常的正确性的程序是错误的:故障快速迭代器应该只用于检测错误。

实施说明:这是一个简单的线性探针哈希表,如 Sedgewick 和 Knuth 的文本中所述。该数组交替保存键和值。 (与使用单独的数组相比,这对于大型表具有更好的局部性。)对于许多 JRE 实现和操作混合,此类将产生比 HashMap(使用链接而不是线性探测)更好的性能。

此类是 Java 集合框架的成员。

嵌套类摘要

从类 java.util.AbstractMap 继承的嵌套类/接口
AbstractMap.SimpleEntryK,V, AbstractMap.SimpleImmutableEntryK,V
从接口 java.util.Map 继承的嵌套类/接口
Map.EntryK,V

构造函数摘要

构造函数 描述
IdentityHashMap() 构造一个具有默认预期最大大小 (21) 的新的空身份哈希映射。
IdentityHashMap(int expectedMaxSize) 构造一个具有指定预期最大大小的新空映射。
IdentityHashMap(Map<? extends K,? extends V> m) 构造一个新的身份哈希映射,其中包含指定映射中的键值映射。

方法总结

修饰符和类型 方法 描述
void clear() 从此 map 中删除所有映射。
Object clone() 返回此身份哈希映射的浅表副本:键和值本身没有被克隆。
boolean containsKey(Object key) 测试指定的对象引用是否是此身份哈希映射中的键。
boolean containsValue(Object value) 测试指定的对象引用是否是此标识哈希映射中的值。
SetMap.EntryK,V entrySet() 返回此映射中包含的映射的 Set 视图。
boolean equals(Object o) 比较指定对象与此映射是否相等。
void forEach(BiConsumer<? super K,? super V> action) 对该映射中的每个条目执行给定的操作,直到处理完所有条目或该操作引发异常。
V get(Object key) 返回指定键映射到的值,如果此映射不包含该键的映射,则返回 null。
int hashCode() 返回此 map 的哈希码值。
boolean isEmpty() 如果此身份哈希映射不包含键值映射,则返回 true。
SetK keySet() 返回此映射中包含的键的基于身份的集合视图。
V put(K key, V value) 将指定值与此身份哈希映射中的指定键相关联。
void putAll(Map<? extends K,? extends V> m) 将所有映射从指定映射复制到此映射。
V remove(Object key) 如果存在,则从此映射中删除此键的映射。
void replaceAll(BiFunction<? super K,? super V,? extends V> function) 将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都已处理或该函数引发异常。
int size() 返回此身份哈希映射中的键值映射的数量。
CollectionV values() 返回此映射中包含的值的集合视图。
从类 java.util.AbstractMap 继承的方法
toString
从接口 java.util.Map 继承的方法
compute, computeIfAbsent, computeIfPresent, getOrDefault, merge, putIfAbsent, remove, replace, replace
从类 java.lang.Object 继承的方法
finalize, getClass, notify, notifyAll, wait, wait, wait

构造函数详细信息

IdentityHashMap

public IdentityHashMap()

构造一个具有默认预期最大大小 (21) 的新的空身份哈希映射。

IdentityHashMap

public IdentityHashMap(int expectedMaxSize)

构造一个具有指定预期最大大小的新空映射。 将超过预期数量的键值映射放入映射可能会导致内部数据结构增长,这可能会有些耗时。

参数:

参数名称 参数描述
expectedMaxSize map 的预期最大尺寸

Throws:

Throw名称 Throw描述
IllegalArgumentException 如果 expectedMaxSize 为负

IdentityHashMap

public IdentityHashMap(Map<? extends K,? extends V> m)

构造一个新的身份哈希映射,其中包含指定映射中的键值映射。

参数:

参数名称 参数描述
m 要将其映射放置到此 map 中的 map

Throws:

Throw名称 Throw描述
NullPointerException 如果指定的 map 为空

方法详情

size

public int size()

返回此身份哈希映射中的键值映射的数量。

指定者:

接口 MapK,V 中的大小

覆盖:

AbstractMapK,V 类中的大小

返回:

此映射中的键值映射的数量

isEmpty

public boolean isEmpty()

如果此身份哈希映射不包含键值映射,则返回 true。

指定者:

接口 MapK,V 中的 isEmpty

覆盖:

AbstractMapK,V 类中的 isEmpty

返回:

如果此身份哈希映射不包含键值映射,则为 true

get

public V get(Object key)

返回指定键映射到的值,如果此映射不包含该键的映射,则返回 null。

更正式地说,如果此映射包含从键 k 到值 v 的映射,使得 (key == k),则此方法返回 v; 否则返回null。 (最多可以有一个这样的映射。)

返回值为 null 并不一定表示该映射不包含该键的映射; 映射也可能将键显式映射为空。 containsKey 操作可用于区分这两种情况。

指定者:

进入接口 MapK,V

覆盖:

进入类 AbstractMapK,V

参数:

参数名称 参数描述
key 要返回其关联值的键

返回:

指定键映射到的值,如果此映射不包含该键的映射,则为 null

containsKey

public boolean containsKey(Object key)

测试指定的对象引用是否是此身份哈希映射中的键。

指定者:

containsKey 在接口 MapK,V

覆盖:

类 AbstractMapK,V 中的 containsKey

参数:

参数名称 参数描述
key 可能的 key

返回:

如果指定的对象引用是此映射中的键,则为 true

containsValue

public boolean containsValue(Object value)

测试指定的对象引用是否是此标识哈希映射中的值。

指定者:

接口 MapK,V 中的 containsValue

覆盖:

类 AbstractMapK,V 中的 containsValue

参数:

参数名称 参数描述
value 要测试其在此映射中的存在的值

返回:

如果此映射将一个或多个键映射到指定的对象引用,则为 true

put

public V put(K key, V value)

将指定值与此身份哈希映射中的指定键相关联。 如果映射先前包含键的映射,则替换旧值。

指定者:

放入接口 MapK,V

覆盖:

放入类 AbstractMapK,V

参数:

参数名称 参数描述
key 与指定值关联的键
value 要与指定键关联的值

返回:

与 key 关联的前一个值,如果没有 key 映射,则返回 null。 (返回 null 还可以指示映射先前将 null 与 key 关联。)

putAll

public void putAll(Map<? extends K,? extends V> m)

将所有映射从指定映射复制到此映射。 这些映射将替换此映射对当前指定映射中的任何键的任何映射。

指定者:

putAll在接口MapK,V中

覆盖:

putAll 在类 AbstractMapK,V

参数:

参数名称 参数描述
m 要存储在此 map 中的映射

Throws:

Throw名称 Throw描述
NullPointerException 如果指定的 map 为空

remove

public V remove(Object key)

如果存在,则从此映射中删除此键的映射。

指定者:

在接口 MapK,V 中删除

覆盖:

在类 AbstractMapK,V 中删除

参数:

参数名称 参数描述
key 要从映射中删除其映射的键

返回:

与 key 关联的前一个值,如果没有 key 映射,则返回 null。 (返回 null 还可以指示映射先前将 null 与 key 关联。)

clear

public void clear()

从此地图中删除所有映射。 此调用返回后,map 将为空。

指定者:

在界面 MapK,V 中清除

覆盖:

在类 AbstractMapK,V 中清除

equals

public boolean equals(Object o)

比较指定对象与此映射是否相等。 如果给定对象也是一个映射并且两个映射表示相同的对象引用映射,则返回 true。 更正式地说,这个映射等于另一个映射 m 当且仅当 this.entrySet().equals(m.entrySet())。

由于此贴图基于引用相等的语义,如果将此贴图与法线贴图进行比较,则可能违反 Object.equals 合约的对称性和传递性要求。 但是,可以保证在 IdentityHashMap 实例中持有 Object.equals 合约。

指定者:

接口 MapK,V 中的等于

覆盖:

类 AbstractMapK,V 中的等于

参数:

参数名称 参数描述
o 要与此 map 比较是否相等的对象

返回:

如果指定的对象等于此 map,则为 true

hashCode

public int hashCode()

返回此 map 的哈希码值。 映射的哈希码定义为映射的 entrySet() 视图中每个条目的哈希码的总和。 这确保了 m1.equals(m2) 意味着 m1.hashCode()==m2.hashCode() 对于任何两个 IdentityHashMap 实例 m1 和 m2,正如 Object#hashCode 的一般合同所要求的那样。

由于此映射的 entrySet 方法返回的集合中 Map.Entry 实例的基于引用相等的语义,如果两个对象之一有可能违反上一段中提到的 Object.hashCode 的合同要求 正在比较的是一个 IdentityHashMap 实例,另一个是法线贴图。

指定者:

接口 MapK,V 中的 hashCode

覆盖:

AbstractMapK,V 类中的 hashCode

返回:

此 map 的哈希码值

clone

public Object clone()

返回此身份哈希映射的浅表副本:键和值本身没有被克隆。

覆盖:

在类 AbstractMapK,V 中克隆

返回:

这张 map 的浅拷贝

keySet

public SetK keySet()

返回此映射中包含的键的基于身份的集合视图。集合由 map 支持,因此对 map 的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射,则迭代的结果是不确定的。该集合支持元素移除,即通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 方法从映射中移除相应的映射。它不支持 add 或 addAll 方法。

虽然此方法返回的对象实现了 Set 接口,但它不遵守 Set 的一般约定。与其支持映射一样,此方法返回的集合将元素相等定义为引用相等而不是对象相等。这会影响其 contains、remove、containsAll、equals 和 hashCode 方法的行为。

仅当指定对象是包含与返回集合完全相同的对象引用的集合时,返回集合的 equals 方法才返回 true。如果将此方法返回的集合与正常集合进行比较,则可能违反 Object.equals 合约的对称性和传递性要求。但是,保证 Object.equals 合约在此方法返回的集合中保持不变。

返回集合的 hashCode 方法返回集合中元素的标识哈希码之和,而不是它们的哈希码之和。这是通过更改 equals 方法的语义来强制执行的,以便在此方法返回的集合中强制执行 Object.hashCode 方法的一般合同。

指定者:

接口 MapK,V 中的 keySet

覆盖:

AbstractMapK,V 类中的 keySet

返回:

此映射中包含的键的基于身份的集合视图

values

public CollectionV values()

返回此映射中包含的值的集合视图。集合由 map 支持,因此对 map 的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射,则迭代的结果是不确定的。该集合支持元素移除,即通过 Iterator.remove、Collection.remove、removeAll、retainAll 和 clear 方法从映射中移除相应的映射。它不支持 add 或 addAll 方法。

虽然此方法返回的对象实现了 Collection 接口,但它不遵守 Collection 的一般约定。与其支持映射一样,此方法返回的集合将元素相等定义为引用相等而不是对象相等。这会影响其 contains、remove 和 containsAll 方法的行为。

指定者:

接口 MapK,V 中的值

覆盖:

AbstractMapK,V 类中的值

返回:

此 map 中包含的值的集合视图

entrySet

public SetMap.EntryK,V entrySet()

返回此映射中包含的映射的 Set 视图。 返回集中的每个元素都是一个基于引用相等的 Map.Entry。 集合由 map 支持,因此对 map 的更改会反映在集合中,反之亦然。 如果在对集合进行迭代时修改了映射,则迭代的结果是不确定的。 该集合支持元素移除,即通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 方法从映射中移除相应的映射。 它不支持 add 或 addAll 方法。

与支持映射一样,此方法返回的集合中的 Map.Entry 对象将键和值相等定义为引用相等而不是对象相等。这会影响这些 Map.Entry 对象的 equals 和 hashCode 方法的行为。基于引用相等的 Map.Entry e 等于对象 o 当且仅当 o 是 Map.Entry 并且 e.getKey()==o.getKey() && e.getValue()==o.getValue( )。为了适应这些等于语义,hashCode 方法返回 System.identityHashCode(e.getKey()) ^ System.identityHashCode(e.getValue())。

由于此方法返回的集合中 Map.Entry 实例的基于引用相等的语义,如果其中的任何条目可能违反 Object#equals(Object) 合约的对称性和传递性要求该集合与法线贴图条目进行比较,或者如果此方法返回的集合与一组法线贴图条目进行比较(例如通过在法线贴图上调用此方法返回)。但是,Object.equals 合约保证在基于身份的映射条目之间以及此类条目的集合之间保持不变。

指定者:

接口 MapK,V 中的 entrySet

指定者:

AbstractMapK,V 类中的 entrySet

返回:

此 map 中包含的身份映射的集合视图

forEach

public void forEach(BiConsumer<? super K,? super V> action)

从接口复制的描述:map

对该映射中的每个条目执行给定的操作,直到处理完所有条目或该操作引发异常。 除非实现类另有规定,否则按照条目集迭代的顺序执行动作(如果指定了迭代顺序)。动作抛出的异常将转发给调用者。

指定者:

接口 MapK,V 中的 forEach

参数:

参数名称 参数描述
action 为每个条目执行的操作

replaceAll

public void replaceAll(BiFunction<? super K,? super V,? extends V> function)

从接口复制的描述:map

将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都已处理或该函数引发异常。 函数抛出的异常被转发给调用者。

指定者:

接口 MapK,V 中的 replaceAll

参数:

参数名称 参数描述
function 应用于每个条目的函数