Java 理论与实践: 哈希
2008-01-05 20:12:57 来源:WEB开发网虽然java语言不直接支持关联数组 -- 可以使用任何对象作为一个索引的数组 -- 但在根Object
类中使用hashCode()
方法明确表示期望广泛使用HashMap
(及其前辈Hashtable
)。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式中支持散列可以促进基于散列的容器的开发和使用。
定义对象的相等性Object
类有两种方法来推断对象的标识:equals()
和hashCode()
。一般来说,假如您忽略了其中一种,您必须同时忽略这两种,因为两者之间有必须维持的至关重要的关系。非凡情况是根据equals()
方法,假如两个对象是相等的,它们必须有相同的hashCode()
值(尽管这通常不是真的)。
特定类的equals()
的语义在Implementer的左侧定义;定义对特定类来说equals()
意味着什么是其设计工作的一部分。Object
提供的缺省实施简单引用下面等式:
public boolean equals(Object obj) { return (this == obj); }
在这种缺省实施情况下,只有它们引用真正同一个对象时这两个引用才是相等的。同样,Object
提供的hashCode()
的缺省实施通过将对象的内存地址对映于一个整数值来生成。由于在某些架构上,地址空间大于int
值的范围,两个不同的对象有相同的hashCode()
是可能的。假如您忽略了hashCode()
,您仍然可以使用System.identityHashCode()
方法来接入这类缺省值。
忽略 equals() -- 简单实例
缺省情况下,equals()
和hashCode()
基于标识的实施是合理的,但对于某些类来说,它们希望放宽等式的定义。例如,Integer
类定义equals()
与下面类似:
public boolean equals(Object obj) {
return (obj instanceof Integer
&& intValue() == ((Integer) obj).intValue());
}
在这个定义中,只有在包含相同的整数值的情况下这两个Integer
对象是相等的。结合将不可修改的Integer
,这使得使用Integer
作为HashMap
中的要害字是切实可行的。这种基于值的Equal方法可以由Java类库中的所有原始封装类使用,如Integer
、Float
、Character
和Boolean
以及String
(假如两个String
对象包含相同顺序的字符,那它们是相等的)。由于这些类都是不可修改的并且可以实施hashCode()
和equals()
,它们都可以做为很好的散列要害字。
为什么忽略 equals()和hashCode()?
假如Integer
不忽略equals()
和 hashCode()
情况又将如何?假如我们从未在HashMap
或其它基于散列的集合中使用Integer
作为要害字的话,什么也不会发生。但是,假如我们在HashMap中
使用这类Integer
对象作为要害字,我们将不能够可靠地检索相关的值,除非我们在get()
调用中使用与put()
调用中极其类似的Integer
实例。这要求确保在我们的整个程序中,只能使用对应于特定整数值的Integer
对象的一个实例。不用说,这种方法极不方便而且错误频频。
Object
的interface contract要求假如根据 equals()
两个对象是相等的,那么它们必须有相同的hashCode()
值。当其识别能力整个包含在equals()
中时,为什么我们的根对象类需要hashCode()
?hashCode()
方法纯粹用于提高效率。Java平台设计人员预计到了典型Java应用程序中基于散列的集合类(Collection Class)的重要性--如Hashtable
、HashMap
和HashSet
,并且使用equals()
与许多对象进行比较在计算方面非常昂贵。使所有Java对象都能够支持 hashCode()
并结合使用基于散列的集合,可以实现有效的存储和检索。
实施equals()和hashCode()的需求
更多精彩
赞助商链接