在本教程中,我们将详细学习JavaIdentityHashMap以及IdentityHashMap 和HashMap的区别。
在比较键(或值)时,IdentityHashMap 使用引用平等而不是对象平等。换句话说,在一个IdentityHashMap ,当且仅当(k1==k2) ,两个键k1 和k2 被认为是相等的。我们可以在IdentityHashMap中使用可变的键,因为引用平等并不随对象的状态而改变。
目录
-
IdentityHashMap简介
IdentityHashMap 类(存在于java.util包中)是一个 基于HashTable的 Map 接口的实现,从*Java 1.4版本*开始就已经存在。
- 这个类不是一个通用的Map 实现。尽管这个类实现了Map 接口,但它违反了Map的一般契约,在比较对象时使用equals() 方法。它使用引用平等(==)来搜索地图中的键。这个类只在需要引用平等的情况下使用。
- IdentityHashMap内部使用System.identityHashCode()方法进行计算。
- IdentityHashMap具有与HashMap几乎相同的特性,包括构造函数和方法。然而,就性能而言,与HashMap相比,它提供了更好的性能,因为它使用了 HashTable 的内联探测技术,而不是*HashMap*使用的链式技术。
- 它的迭代器在迭代过程中试图修改地图时抛出ConcurrentModificationException。
- 它不是一个线程安全的类。使用*Collections.synchronizedMap()*来获得这个类的线程安全引用。
在Java集合 中, 类被声明如下。
public class IdentityHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Serializable, Cloneable
如上所示,它实现了Map 接口并扩展了AbstractMap 类。
2.使用IdentityHashMap工作
2.1 创建IdentityHashMap
我们可以通过使用以下构造函数来创建IdentityHashMap 。
IdentityHashMap(): 用来创建一个初始默认容量为21的空地图。IdentityHashMap(int initialCapacity):用来创建一个具有给定初始容量的空地图。IdentityHashMap(Map m):用于创建一个新的IdentityHashMap ,其条目与指定地图相同。
IdentityHashMap<String, String> map = new IdentityHashMap<>();
IdentityHashMap<String, String> map = new IdentityHashMap<>(16);
Map<String, String> map = new HashMap<String, String>() {{
put("key1", "value1");
put("key2", "value2");
}};
IdentityHashMap<String, String> map = new IdentityHashMap<>(map);
2.2IdentityHashMap方法
该类中一些经常使用的方法是。
Object put(key, value):向地图中插入一个键值对。Object get(key):返回地图中指定键的值。boolean containsKey(key):根据是否在地图中找到指定的键,返回true或false。boolean containsValue(value):类似于*containsKey()*方法,它寻找的是指定的值而不是key。Set keySet():返回存储在地图中的所有键的集合 。Set entrySet():返回存储在地图中的所有映射的集合 。Value remove(Object key):删除指定键的键值对。int size():返回地图的大小,等于地图中存储的键值对的数量。
2.3IdentityHashMap 例子
让我们快速介绍一个创建其实例的例子 ,以及我们如何使用上面描述的方法。
//Creating IdentityHashMap
IdentityHashMap<Integer, String> map = new IdentityHashMap<>();
//Adding values to map using put()
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
System.out.println(map);
//Getting a value from the map
String value = map.get(2);
System.out.println(value);
//Checking if a key or value present in the map
System.out.println(map.containsKey(3));
System.out.println(map.containsValue("Z"));
//Removing an entry
map.remove(3);
System.out.println(map);
//Finding map size
System.out.println(map.size());
//Iterating over the map
for(Map.Entry<Integer, String> entry : map.entrySet())
{
System.out.println(entry.getKey() + " :: " + entry.getValue());
}
注意,IdentityHashMap支持null 键和值。
IdentityHashMap<String, String> map = new IdentityHashMap<>();
map.put(null, "Some Value"); //Null key
map.put("Some Key", null); //Null value
3.HashMap 和IdentityHashMap之间的区别
3.1 引用平等性
在比较键 (和值)时,IdentityHashMap使用引用相等(==)而不是Map的 equals()方法。让我们通过一个例子来理解。
// Two similar keys but different instances in memory
Integer key1 = new Integer(10);
Integer key2 = new Integer(10);
// Same keys in IdentityHashMap
IdentityHashMap<Integer, String> identityHashMap = new IdentityHashMap<>();
identityHashMap.put(key1, "India");
identityHashMap.put(key2, "USA");
System.out.println("Identity HashMap : " + identityHashMap);
// Same keys in HashMap
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(key1, "India");
hashMap.put(key2, "USA");
System.out.println("HashMap : " + hashMap);
注意程序的输出。HashMap拒绝了第二个键,因为它使用*equals()*方法对键进行了比较,对于这两个键来说,其值都是10。IdentityHashMap使用的是引用相等,而两个键都是单独存储在内存中的,所以它们的引用将是不相等的。
当我们把键值对放到HashMap中时,它就会更新之前的条目,我们就会得到一个存储在Map中的单一条目。
Identity HashMap : {10=USA, 10=India}
HashMap : {10=USA}
3.2 可变键
我们可以在IdentityHashMap 中使用可变键,而对于HashMap ,我们总是建议使用不可变的键。
让我们通过一个例子来理解,创建一个可变类 "Vehicle"。定义必要的访问器方法,hashCode()和equals()方法。
class Vehicle {
private String name;
private int year;
public Vehicle(String name, int year) {
this.name = name;
this.year = year;
}
//Getters and Setters
@Override
public String toString() {
return "Vehicle{" +
"vehicleName='" + name + '\'' +
", modelYear=" + year +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Vehicle vehicle = (Vehicle) o;
if (Objects.equals(year, vehicle.year)) return false;
return Objects.equals(name, vehicle.name);
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + year;
return result;
}
}
我们将向地图添加一些键值对,然后改变键和值的状态。然后,我们将使用改变后的键来获取条目,这应该会返回原来的值。
Vehicle vehicle = new Vehicle("Honda", 2015);
Map<Vehicle, String> identityHashMap1 = new IdentityHashMap<>();
identityHashMap1.put(vehicle, "Old Vehicle");
// Changing key state
vehicle.setName("Modified Vehicle");
vehicle.setYear(2022);
// Getting value for key vehicle from the map
System.out.println( identityHashMap1.get(vehicle) ); //Prints 'Modified Vehicle'
4.身份哈希图 的用例
IdentityHashMap用于少数情况,我们在使用这个类时必须小心。
它有助于构建特定的框架,包括。
- Spring Bean或Singleton类型,因为它们精确地管理某些类型的一个实例
- 为一组易变的对象维护代理对象
- 类对象,因为它们也可以通过引用进行比较。
- 基于一个对象引用的缓存实例
- 保持一个有引用的 对象的内存图
5.总结
我们了解了Java中的IdentityHashMap,它的内部工作原理以及它与HashMap的区别。我们还介绍了涉及HashMap和 IdentityHashMap的实际例子,以及它们在按键比较方面的不同表现。
学习愉快
这篇文章有帮助吗?
如果你喜欢这篇文章,请告诉我们。这是我们改进的唯一方法。
有
没有