JavaTutorials在IdentityHashMap上有这样的说法
identity-based
Map是基于哈希表的IdentityHashMap实现。这个类对于保持拓扑的对象图转换(如序列化或深度复制)非常有用.要执行这样的转换,您需要维护一个基于身份的“节点表”,该表跟踪已经看到哪些对象。基于标识的映射也用于维护动态调试器和类似系统中的对象到元信息映射。最后,基于身份的映射在阻止“欺骗攻击”方面非常有用,这些攻击是由于故意使用的不正确的等于方法造成的,因为IdentityHashMap从不在其键上调用equals方法。这种实现的另一个好处是它速度快。
有谁能用简单的英语解释一下这两者的意思吗?
发布于 2017-01-11 10:43:03
读Javadoc --如果你需要理解一个类的话,你总是应该读的。
该类使用哈希表实现Map接口,在比较键(和值)时使用引用相等代替对象相等。换句话说,在
IdentityHashMap中,k1和k2两个键被认为是相等的当且仅当(k1==k2)。(在普通地图实现(如HashMap)中,k1和k2两个键被认为是相等的当且仅当(k1==null ? k2==null : k1.equals(k2))。
和
这个类的一个典型用法是保持拓扑的对象图转换,例如序列化或深度复制.要执行这样的转换,程序必须维护一个“节点表”,该表跟踪已经处理的所有对象引用。节点表不能等同于不同的对象,即使它们恰好相等。
发布于 2017-01-11 11:43:07
“基于身份的Map”意味着通过==对键进行标识比较,而不是通过equals进行平等比较。
“拓扑-保持对象图变换”是指当您有某种对象结构并将其转换为另一个对象结构时,您希望保留拓扑,即原始图和目标图中节点之间的关系。为此,您需要通过标识(而不是等式)映射节点。
考虑下面的例子。您有Foo类树(通过Foo parent字段定义的树),希望将其转换为树Bar类(同样是Bar有Bar parent)字段。对于每个Foo,您都需要创建一个新的Bar,但只需要创建一次。为了跟踪该映射,您将创建一个Map<Foo, Bar>。您还将使用此映射查找父Bar的。
但是,问题是,如果两个Foo是equals,那么在从跟踪地图中获取它时,您可能会得到错误的父Bar。这将破坏Bar树中的拓扑结构,只需将节点挂起错误的父节点即可。
为了避免这种情况,您需要身份比较,而不是平等。这就是IdentitiyHashMap所做的。
发布于 2017-01-11 11:57:15
一个简单的代码比千言万语要好,见下文:-
public static void main(String[] args){
//Two Keys
Integer key1=new Integer("1");
Integer key2=new Integer("1");
//A normal map
Map<Integer, String> map=new HashMap<Integer, String>();
map.put(key1, "Hello");
map.put(key2, "World");
System.out.println(map); //Output:- {1=World}
//An identity HashMap
Map<Integer, String> identityMap=new IdentityHashMap<Integer, String>();
identityMap.put(key1, "Hello");
identityMap.put(key2, "World");
System.out.println(identityMap); //Output:- {1=Hello, 1=World}
}你在上面观察到:-
因此,对于IdentityHashMap,两个键是相等的当且仅当它们引用内存中相同的位置即标识相等,因此这个映射是一个只支持基于身份的平等的特殊实现。
对象具有对其他对象的引用,而其他对象又可能有对更多对象的引用,这将导致对象图。
如果您想要转换对象图并维护对象关系,您将在Type,即引用,而不是对象的实际值上进行转换。如果使用IdentityHashMap,它将保留对象引用的原始拓扑,因为它不依赖于hashCode(..)并等于(.)对象的方法。
https://stackoverflow.com/questions/41588440
复制相似问题