IdentityHashMap
java.util.IdentityHashMap类利用哈希表实现 Map 接口,比较键(和值)时使用引用相等性代替对象相等性。 换句话说,在 IdentityHashMap 中,当且仅当 (k1==k2) 时,
才认为两个键 k1 和 k2 相等(在正常 Map 实现(如 HashMap)中,当且仅当满足下列条件时才认为两个键 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。
此类不是 通用 Map实现!此类实现Map接口时,它有意违反Map的常规协定比较对象时强制使用equals方法。此类设计仅用于其中需要引用相等性语义的罕见情况。
此类的典型用法是拓扑保留对象图形转换,如序列化或深层复制。 要执行这样的转换,程序必须维护用于跟踪所有已处理对象引用的“节点表”。
节点表一定不等于不同对象,即使它们偶然相等也如此。
此类的另一种典型用法是维护代理对象。例如,调试设施可能希望为正在调试程序中的每个对象维护代理对象。
此类提供所有的可选映射操作,并且允许 null 值和 null 键。此类对映射的顺序不提供任何保证;特别是不保证顺序随时间的推移保持不变。
此类提供基本操作(get 和 put)的稳定性能,假定系统标识了将桶间元素正确分开的哈希函数 (System.identityHashCode(Object))。
此类具有一个调整参数(影响性能但不影响语义):expected maximum size。此参数是希望映射保持的键值映射关系最大数。在内部,此参数用于确定最初组成哈希表的桶数。
未指定所期望的最大数量和桶数之间的确切关系。默认的价值加载因子为2/3,在重新哈希后,加载因子变为1/3.当哈希表中的条目数超出了加载因子与当前容量的乘积时,
通过调用 reszie 方法将容量翻倍,重新进行哈希。增加桶数,重新哈希,可能相当昂贵。因此创建具有足够大的期望最大数量的标识哈希映射更合算。
注意,此实现不是同步的。如果多个线程同时访问此映射,并且其中至少一个线程从结构上修改了该映射,
则其必须保持外部同步(结构上的修改是指添加或删除一个或多个映射关系的操作;仅改变与实例已经包含的键关联的值不是结构上的修改)。
一般通过对封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用Collections.synchronizedMap方法来“包装”该映射。
最好在创建时完成这一操作,以防止对映射进行意外的不同步访问,如下所示:
Map m = Collections.synchronizedMap(new HashMap(...));
由所有此类的“collection 视图方法”所返回的迭代器都是快速失败的:在迭代器创建之后, 如果从结构上对映射进行修改,除非通过迭代器自身的 remove 或 add 方法,
其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。 因此面对并发的修改,迭代器很快就会失败,而不会在将来不确定的时间任意发生不确定行为的风险。
注意,此类迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何强有力的保证。
因此,编写依赖于此异常的程序的方式是错误的,正确做法是: 迭代器的快速失败行为应该仅用于检测程序错误。
实现注意事项:此为简单的线性探头哈希表,如Sedgewick 和 Knuth 原文示例中所述。 该数组交替保持键和值(对于大型表来说,它比使用独立组保持键和值更具优势)。
对于多数 JRE 实现和混合操作, 此类比 HashMap(它使用链 而不使用线性探头)能产生更好的性能。
注意1:允许 null 值和 null 键。
注意2:此类对映射的顺序不提供任何保证;特别是不保证顺序随时间的推移保持不变。
注意3:此实现不是同步的。
注意4:迭代器的快速失败行为不能得到保证。
注意5:此为简单的线性探头哈希表。对于多数 JRE 实现和混合操作, 此类比HashMap(它使用链而不使用线性探头)能产生更好的性能。
| Public Constructors | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| IdentityHashMap()
Creates an IdentityHashMap with default expected maximum size.
|
|||||||||||
| IdentityHashMap(int maxSize)
Creates an IdentityHashMap with the specified maximum size parameter.
|
|||||||||||
| IdentityHashMap(Map<? extends K, ? extends V> map)
Creates an IdentityHashMap using the given map as initial values.
|
|||||||||||
package test; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; class Person { // 定义Person类 private String name; // 定义name属性 private int age; // 定义age属性 public Person(String name, int age) { // 通过构造方法为属性赋值 this.name = name; // 为name属性赋值 this.age = age; // 为age属性赋值 } public boolean equals(Object obj) { // 覆写equals()方法 if (this == obj) { // 判断地址是否相等 return true; // 返回true表示同一对象 } if (!(obj instanceof Person)) { // 传递进来的不是本类的对象 return false; // 返回false表示不是同一对象 } Person p = (Person) obj; // 进行向下转型 if (this.name.equals(p.name) && this.age == p.age) { return true ; // 属性依次比较,相等返回true }else{ return false ; // 属性内容不相等,返回false } } public int hashCode(){ // 覆写hashCode()方法 return this.name.hashCode() * this.age ; // 计算公式 } public String toString() { // 覆写toString()方法 return "姓名:" + this.name + ";年龄:" + this.age; // 返回信息 } } public class IdentityHashMapDemo { public static void main(String[] args) { Map<Person, String> map = null;// 声明Map对象,指定泛型类型 map = new IdentityHashMap<Person, String>();//实例化Map对象 map.put(new Person("张三", 30), "zhangsan_1");//增加内容 map.put(new Person("张三", 30), "zhangsan_2");//增加内容,key重复 map.put(new Person("李四", 31), "lisi");//增加内容 Set<Map.Entry<Person, String>> allSet = null;//声明一个Set集合 allSet = map.entrySet();// 将Map接口实例变为Set接口实例 Iterator<Map.Entry<Person, String>> iter = null;// 声明Iterator对象 iter = allSet.iterator(); //实例化Iterator对象 while (iter.hasNext()) {// 迭代输出 Map.Entry<Person, String> me = iter.next();// 每个对象都是Map.Entry实例 System.out.println(me.getKey()+ " --> " + me.getValue());// 输出key和value } } }
输出如下:
姓名:李四;年龄:31 --> lisi 姓名:张三;年龄:30 --> zhangsan_1 姓名:张三;年龄:30 --> zhangsan_2
浙公网安备 33010602011771号