每个Java对象都有hashCode()和 equals()方法。许多类忽略(Override)这些方法的缺省实施,以在对象实例之间提供更深层次的语义可比性。在Java理念和实践这一部分,Java开发人员Brian Goetz向您介绍在创建Java类以有效和准确定义hashCode()和equals()时应遵循的规则和指南。您可以在讨论论坛与作者和其它读者一同探讨您对本文的看法。(您还可以点击本文顶部或底部的讨论进入论坛。)
虽然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()的需求
实施equals()和 hashCode()有一些限制,Object文件中列举出了这些限制。特别是equals()方法必须显示以下属性:
Symmetry:两个引用,a和 b,a.equals(b) if and only if b.equals(a)
Reflexivity:所有非空引用, a.equals(a)
Transitivity:If a.equals(b) and b.equals(c), then a.equals(c)
Consistency with hashCode():两个相等的对象必须有相同的hashCode()值
Object的规范中并没有明确要求equals()和 hashCode() 必须一致 -- 它们的结果在随后的调用中将是相同的,假设“不改变对象相等性比较中使用的任何信息。”这听起来象“计算的结果将不改变,除非实际情况如此。”这一模糊声明通常解释为相等性和散列值计算应是对象的可确定性功能,而不是其它。
对象相等性意味着什么?
人们很容易满足Object类规范对equals() 和 hashCode() 的要求。决定是否和如何忽略equals()除了判断以外,还要求其它。在简单的不可修值类中,如Integer(事实上是几乎所有不可修改的类),选择相当明显 -- 相等性应基于基本对象状态的相等性。在Integer情况下,对象的唯一状态是基本的整数值。
对于可修改对象来说,答案并不总是如此清楚。equals() 和hashCode() 是否应基于对象的标识(象缺省实施)或对象的状态(象Integer和String)?没有简单的答案 -- 它取决于类的计划使用。对于象List和Map这样的容器来说,人们对此争论不已。Java类库中的大多数类,包括容器类,错误出现在根据对象状态来提供equals()和hashCode()实施。
如果对象的hashCode()值可以基于其状态进行更改,那么当使用这类对象作为基于散列的集合中的关键字时我们必须注意,确保当它们用于作为散列关键字时,我们并不允许更改它们的状态。所有基于散列的集合假设,当对象的散列值用于作为集合中的关键字时它不会改变。如果当关键字在集合中时它的散列代码被更改,那么将产生一些不可预测和容易混淆的结果。实践过程中这通常不是问题 -- 我们并不经常使用象List这样的可修改对象做为HashMap中的关键字。
一个简单的可修改类的例子是Point,它根据状态来定义equals()和hashCode()。如果两个Point 对象引用相同的(x, y)座标,Point的散列值来源于x和y座标值的IEEE 754-bit表示,那么它们是相等的。
对于比较复杂的类来说,equals()和hashCode()的行为可能甚至受到superclass或interface的影响。例如,List接口要求如果并且只有另一个对象是List,而且它们有相同顺序的相同的Elements(由Element上的Object.equals() 定义),List对象等于另一个对象。hashCode()的需求更特殊--list的hashCode()值必须符合以下计算:
hashCode = 1;
Iterator i = list.iterator();
while (i.hasNext()) {
Object obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
不仅仅散列值取决于list的内容,而且还规定了结合各个Element的散列值的特殊算法。(String类规定类似的算法用于计算String的散列值。)
编写自己的equals()和hashCode()方法
忽略缺省的equals()方法比较简单,但如果不违反对称(Symmetry)或传递性(Transitivity)需求,忽略已经忽略的equals() 方法极其棘手。当忽略equals()时,您应该总是在equals()中包括一些Javadoc注释,以帮助那些希望能够正确扩展您的类的用户。
作为一个简单的例子,考虑以下类:
class A {
final B someNonNullField;
C someOtherField;
int someNonStateField;
}
我们应如何编写该类的equals()的方法?这种方法适用于许多情况:
public boolean equals(Object other) {
// Not strictly necessary, but often a good optimization
if (this == other)
return true;
if (!(other instanceof A))
return false;
A otherA = (A) other;
return
(someNonNullField.equals(otherA.someNonNullField))
&& ((someOtherField == null)
? otherA.someOtherField == null
: someOtherField.equals(otherA.someOtherField)));
}
现在我们定义了equals(),我们必须以统一的方法来定义hashCode()。一种统一但并不总是有效的定义hashCode()的方法如下:
public int hashCode() { return 0; }
这种方法将生成大量的条目并显著降低HashMaps的性能,但它符合规范。一个更合理的hashCode()实施应该是这样:
public int hashCode() {
int hash = 1;
hash = hash * 31 + someNonNullField.hashCode();
hash = hash * 31
+ (someOtherField == null ? 0 : someOtherField.hashCode());
return hash;
}
注意:这两种实施都降低了类状态字段的equals()或hashCode()方法一定比例的计算能力。根据您使用的类,您可能希望降低superclass的equals()或hashCode()功能一部分计算能力。对于原始字段来说,在相关的封装类中有helper功能,可以帮助创建散列值,如Float.floatToIntBits。
编写一个完美的equals()方法是不现实的。通常,当扩展一个自身忽略了equals()的instantiable类时,忽略equals()是不切实际的,而且编写将被忽略的equals()方法(如在抽象类中)不同于为具体类编写equals()方法。关于实例以及说明的更详细信息请参阅Effective Java Programming Language Guide, Item 7 (参考资料) 。
有待改进?
将散列法构建到Java类库的根对象类中是一种非常明智的设计折衷方法 -- 它使使用基于散列的容器变得如此简单和高效。但是,人们对Java类库中的散列算法和对象相等性的方法和实施提出了许多批评。java.util中基于散列的容器非常方便和简便易用,但可能不适用于需要非常高性能的应用程序。虽然其中大部分将不会改变,但当您设计严重依赖于基于散列的容器效率的应用程序时必须考虑这些因素,它们包括:
太小的散列范围。使用int而不是long作为hashCode()的返回类型增加了散列冲突的几率。
糟糕的散列值分配。短strings和小型integers的散列值是它们自己的小整数,接近于其它“邻近”对象的散列值。一个循规导矩(Well-behaved)的散列函数将在该散列范围内更均匀地分配散列值。
无定义的散列操作。虽然某些类,如String和List,定义了将其Element的散列值结合到一个散列值中使用的散列算法,但语言规范不定义将多个对象的散列值结合到新散列值中的任何批准的方法。我们在前面编写自己的equals()和hashCode()方法中讨论的List、String或实例类A使用的诀窍都很简单,但算术上还远远不够完美。类库不提供任何散列算法的方便实施,它可以简化更先进的hashCode()实施的创建。
当扩展已经忽略了equals()的 instantiable类时很难编写equals()。当扩展已经忽略了equals()的 instantiable类时,定义equals()的“显而易见的”方式都不能满足equals()方法的对称或传递性需求。这意味着当忽略equals()时,您必须了解您正在扩展的类的结构和实施详细信息,甚至需要暴露基本类中的机密字段,它违反了面向对象的设计的原则。
结束语
通过统一定义equals()和hashCode(),您可以提升类作为基于散列的集合中的关键字的使用性。有两种方法来定义对象的相等性和散列值:基于标识,它是Object提供的缺省方法;基于状态,它要求忽略equals()和hashCode()。当对象的状态更改时如果对象的散列值发生变化,确信当状态作为散列关键字使用时您不允许更更改其状态。


72.36.192.* 于 2007-05-14 14:36:28发表:
Good design!
free christian ringtones | ringtones cingular | free ringtones for boost mobile | ringtone midi | sms ringtones | ringtones verizon | cellular south ringtones | 24 ring tone | 50 cent ringtones | free blackberry ringtones
72.36.192.* 于 2007-05-14 14:35:57发表:
Well done!
free ringtones for cricket | mosquito ringtone | free ringtones for samsung | free centennial wireless ringtones | mobile ringtones | ctu ringtone | free mp3 ringtone download | free ringtones for motorola | 24 ctu ringtones | free motorola ringtone downloads
72.36.192.* 于 2007-05-14 14:35:34发表:
Good design!
download free motorola ringtone | free ringtone creator | star wars ringtones | real music ringtones | ctu ring tone | ringtone ctu | lg ringtones | free sprint pcs ringtones | kyocera ringtones | download free mp3 ringtones
72.36.192.* 于 2007-05-14 14:35:06发表:
Good design!
free cell phone ring tones | motorola razr v3 ringtones | ringtones for tracfone | alltel free ringtones | download free polyphonic ringtones | wav ringtones | voice ringtone | free sprint ringtones | arabic ringtones | midi ringtones
72.36.192.* 于 2007-05-14 14:34:36发表:
Thank you!
crazy frog ringtones | ringtone websites | ringtones composer | download free nokia ringtone | free harry potter ringtones | downloadable ringtones | free ringtones samsung | free suncom ringtones | crazy frog ringtone | free ringtones mp3
72.36.192.* 于 2007-05-13 10:07:49发表:
Good design!
free phone downloads | ringtones for alltel | jamster ringtones | free sanyo ringtones | tracfone ringtones | free sprint ringtones | free mp3 ringtone downloads | free kyocera ringtones | us cellular ringtones | free real tone ringtones
72.36.192.* 于 2007-05-13 10:07:19发表:
Nice site!
sanyo ringtones | harry potter ringtone | online ringtone converter | suncom ringtones | cricket ringtones | hindi ringtone | free gospel ringtones | free ringtones alltel | mosquito ringtone | free us cellular ring tones
72.36.192.* 于 2007-05-13 10:06:42发表:
Great work!
free ringtones mp3 | nokia downloads | free sprint downloads | motorola q ringtones | free verizon ringtones | free polyphonic | mp3 ringtones download | cisco ringtones | free mp3 ringtones | free nokia ringtone
72.36.192.* 于 2007-05-13 10:06:21发表:
Nice site!
ringtones nokia | nextel ringtones | motorola ringtone | lg ringtones | free anime ringtones | eminem ringtones | ringtones midi | 24 ring tone | ringtones for verizon | free cingular ringtones
72.36.192.* 于 2007-05-13 10:06:09发表:
Great work!
motorola mp3 ringtones | free t mobile ringtones | star wars ringtones | free bollywood ringtones | arabic ringtones | ctu ringtone | 24 ringtone free | free motorola ringtones | sprint pcs ringtones | ringtone
72.36.192.* 于 2007-05-11 18:18:12发表:
Great work!
mosquito ringtone | nextel ringtones | free nascar ringtones | free anime | real music ringtones | free mp3 ringtone | ringtone mp3 | sms ringtones | ring tones | ringtone websites
72.36.192.* 于 2007-05-11 18:17:46发表:
Good design!
hifi ringtones | free ringtones for sprint phones | free star wars ringtones | cell phone ringtones | cheap ringtones | free mp3 ringtones | free hifi ringtones | nextel ringtone | mp3 to ringtone converter | cellular one ringtones
72.36.192.* 于 2007-05-11 18:17:18发表:
Thank you!
24 ctu ringtone | verizon ringtones free | free mp3 ringtone download | free ctu ringtone | free midi ringtone | free cingular cell phone ringtones | free polyphonic ringtone download | ringtones for us cellular | free motorola ringtones | verizon free ringtones
72.36.192.* 于 2007-05-11 18:16:54发表:
Well done!
free wav ringtones | samsung free ringtones | ringtones mp3 | download ringtones | wwe ringtones | free sprint downloads | ringtone jukebox | sprint ringtones | cingular wireless ringtones | mosquito ring tone
72.36.192.* 于 2007-05-11 18:16:18发表:
Thank you!
free ringtones for tracfone | suncom ringtones | ringtones samsung | ringtones for alltel | free ringtones for alltel | ringtones download | free boost mobile ringtones | free ringtones verizon | free polyphonic ringtone | lg ringtones
72.36.192.* 于 2007-05-10 20:53:03发表:
Good design!
free gambling games | casino open usa | video slot machines | internet poker | virtual poker | games download | no deposit bonus | download casino games | new casinos | free poker websites
72.36.192.* 于 2007-05-10 20:52:37发表:
Well done!
play poker for free | best bonus casino | free bingo | play roulette for free | slot machine free | online baccarat | free online texas hold em | free blackjack online | free blackjack | slots for free
72.36.192.* 于 2007-05-10 20:52:08发表:
Great work!
play slots for fun | free online casino games | live poker | free casino downloads | poker game online | monopoly slot machine | black jack game | free online poker games | free slot games no download | blackjack for free
72.36.192.* 于 2007-05-10 20:51:40发表:
Good design!
free online casino | free slim slots | party poker | no deposit casinos | casino free game online | free play slot machines | free online roulette | play bingo online | slot games free | play texas holdem
72.36.192.* 于 2007-05-10 20:51:15发表:
Great work!
free money casinos | free slot game | online black jack | free bonus slots | free texas holdem | play slots for free | free slots | poker online | poker websites | slots games
72.36.192.* 于 2007-05-09 19:48:10发表:
Great work!
casino download | free online roulette | free online slot games | no deposit bonus casinos | casino bonuses | play roulette online | free bingo online | play online poker | free video poker | slots for fun
72.36.192.* 于 2007-05-09 19:47:42发表:
Good design!
play poker for free | blackjack download | casino game | blackjack games | no deposit casino bonus | video poker machines | free blackjack | world series of poker download | bonus casino free online | black jack game
72.36.192.* 于 2007-05-09 19:47:19发表:
Good design!
free online casino | free money no deposit | texas hold em free | free slots game | video slot machines | free video | monopoly online | free slots | poker sites | casino deposit bonus
72.36.192.* 于 2007-05-09 19:46:43发表:
Good design!
free games on line | free poker online | best bonus casino | free black jack | blackjack free | casino on line | free online poker | free three card poker | roulette download | flash casino games
72.36.192.* 于 2007-05-09 19:46:21发表:
Great work!
free online texas hold em | video poker | cleopatra slot machine | virtual poker | poker bonus | pacific poker | no deposit bonus | free monopoly slots | free poker games | online texas holdem
72.36.192.* 于 2007-05-08 20:04:24发表:
Good design!
strip blackjack | slot machines | poker stars download | free poker game | free roulette online | online poker game | free casino slots | video poker download | online games | game slot
72.36.192.* 于 2007-05-08 20:03:54发表:
Great work!
online black jack | free poker sites | play slot machines | online poker games | free play slot machines | poker websites | online video slots | no deposit online casinos | slot game | slots download
72.36.192.* 于 2007-05-08 20:03:27发表:
Great work!
online baccarat | play blackjack free | new no deposit casino | play online poker | free online bingo | download blackjack | free poker games | free online poker game | free poker game download | free online casino
72.36.192.* 于 2007-05-08 20:03:01发表:
Nice site!
online roulette game | free casino games | free slot machine games online | download casino | online roulette | free slots download | blackjack free | free online blackjack | slot machine game | free video slots
72.36.192.* 于 2007-05-08 20:02:27发表:
Nice site!
slots online | free roulette games | free texas hold em online | full tilt poker | free monopoly slots | free slot play | free slot machines games | online poker free | online gambling | free online bingo games
72.36.192.* 于 2007-05-07 19:14:44发表:
Nice site!
ringtone free | mp3 ringtones download | crazy frog ringtones | free motorola ringtone downloads | us cellular ring tones | cellphone ringtones | free ringtone converter | free ringtones samsung | ringtones for motorola q | ringtones samsung
72.36.192.* 于 2007-05-07 19:14:17发表:
Thank you!
cricket ringtones | ringtones for tracfones | free nextel ringtones | free ringtones downloads | ringtones for alltel | verizon ringtones | free tmobile ringtones | mp3 ringtone | ringtones verizon | free nokia downloads
72.36.192.* 于 2007-05-07 19:13:53发表:
Great work!
sprint pcs ringtones | free ringtone | free blackberry ringtones | ctu 24 ringtone | free polyphonic ringtones | ringtones for verizon | nokia free ringtones | funny ringtones | cell phone ringtones | free ringtones for sprint phones
72.36.192.* 于 2007-05-07 19:13:21发表:
Good design!
free us cellular ring tones | free ringtones for lg | christian music ringtones | ringtones wav | motorola mp3 ringtones | ringtone jukebox | ringtones download | motorola free ringtones | us cellular ringtones | ringtones for suncom
72.36.192.* 于 2007-05-07 19:12:52发表:
Thank you!
free t mobile ringtones | free ringtone creator | funny ringtone | centennial wireless | free country music ringtones | 24 ctu ringtone | free cellular one ringtones | free ringtones for u s cellular | free cellular south ringtones | ringtones mp3
72.36.192.* 于 2007-05-06 19:51:27发表:
Thank you!
roulette download | casino slots | free casino game | free slot downloads | play free blackjack online | play bingo | no deposit casino bonuses | free strip black jack | black jack games | slot machines games
72.36.192.* 于 2007-05-06 19:50:58发表:
Well done!
on line poker | world series of poker | gambling sites | internet gambling | cleopatra slots | casino poker | on line casinos | online baccarat | monopoly online | strip blackjack
72.36.192.* 于 2007-05-06 19:50:37发表:
Great work!
poker | free games online | three card poker | free texas holdem | free slots | free multi line slots | free online casinos | online blackjack free | texas hold em online | free sim slots
72.36.192.* 于 2007-05-06 19:50:06发表:
Good design!
poker online | free online texas holdem | no deposit online casinos | download slots | download party poker | online roulette | free bingo | free money no deposit | casino bonuses | slots free
72.36.192.* 于 2007-05-06 19:49:37发表:
Good design!
free online poker | roulette free games | free slots downloads | free slot machine game | slot machine | play slots for fun | free online slot machine games | video poker free | poker game download | play money poker