Apache Commons 项目运用 - hashCode篇

原创 2012年03月28日 22:03:29
对象的散列
实现一个适当的 equals 方法后别忘了还要覆盖 hashCode。本节展示如何操作。
构建 hashCode
hashCode 方法也有一个契约,但是不像 equals 的契约那样正式。然而,重要的是要理解它。和 equals 一样,结果必须一致。对于对象 foo 和 bar,如果 foo.equals(bar) 返回 true,那么 foo 和 bar 的 hashCode 方法必须返回相同的值。如果 foo 和 bar 不相等,则不要求返回不同的散列码。但是,Javadocs 提到,如果这些对象有不同的结果,那么通常会运行得更好一些。
还需注意,和之前一样,如果没有覆盖它,hashCode 会返回一个看似随机的整数。这是因为底层平台通常会将基对象的地址位置转换成一个整数;虽然如此,但文档中提到这并不是必需的,因此可以改变。无论如何,如果最终覆盖 equals 方法,那么也有必要覆盖 hashCode 方法。(记住,虽然 hashCode 方法看上去是开箱即用的,但是 Joshua Bloch 的 Effective Java 花了 6 页的篇幅讨论如何适当地实现 hashCode 方法)。
Commons Lang 库提供一个 HashCodeBuilder 类,这个类与 EqualsBuilder 几乎是一样的。但是,它不是比较两个属性,而是附加一个属性,以生成遵从我刚才描述的契约的一个整数。
在您的 Account 对象中,覆盖 hashCode 方法,如例 9 所示:

例 9. 默认的 hashCode 方法
					
public int hashCode() {
 return 0;
}

由于生成一个散列码时没有什么可以比较的,因此使用 HashCodeBuilder 只需一行代码。重要的是正确地初始化 HashCodeBuilder。构造函数带有两个 int,它使用这两个参数来创建一个散列码。这两个 int 必须是奇数。append 方法带有一个属性,因此,和之前一样,这些方法可以链接起来。最后可以通过调用 toHashCode 方法完成这个链。
根据这些信息,您可以像例 10 中那样实现一个 hashCode 方法:

例 10. 用 HashCodeBuilder 实现一个 hashCode 方法
					
public int hashCode() {
 return new HashCodeBuilder(11, 21)。append(this.id)
  .append(this.firstName)
   .append(this.lastName)
    .append(this.emailAddress)
     .append(this.creationDate)
      .toHashCode();
}

注意,我在构造函数中传入了一个 11 和一个 21。这些完全是为该对象随机选择的奇数。打开前面的 AccountTest(参见 例 2)。添加一个快速检查,以验证如下契约:对于这两个对象,如果 equals 返回 true,那么 hashCode 应该返回相同的数字。例 11 显示了修改后的测试:

例 11. 验证 hashCode 关于两个相等对象的契约
					
import org.junit.Test;
import org.junit.Assert;
import com.acme.app.Account;

import java.util.Date;

public class AccountTest {
 @Test
 public void verifyAccountEquals(){
  Date now = new Date();
  Account acct1 = new Account(1, "Andrew", "Glover", "ajg@me.com", now);
  Account acct2 = new Account(1, "Andrew", "Glover", "ajg@me.com", now);

  Assert.assertTrue(acct1.equals(acct2));
  Assert.assertEquals(acct1.hashCode(), acct2.hashCode());
 }
}

在例 11 中,我验证了两个相等的对象具有相同的散列码。接下来,在例 12 中,我还验证两个不同的 对象具有不同的散列码:

例 12. 验证 hashCode 关于两个不同的对象的契约
					
@Test
public void verifyAccountDifferentHashCodes(){
 Date now = new Date();
 Account acct1 = new Account(1, "John", "Smith", "john@smith.com", now);
 Account acct2 = new Account(2, "Andrew", "Glover", "ajg@me.com", now);

 Assert.assertFalse(acct1.equals(acct2));
 Assert.assertTrue(acct1.hashCode() != acct2.hashCode());
}

如果您出于好奇想自己编写一个 hashCode 方法,应该怎么做呢?记住 hashCode 契约,您可以编写如例 13 所示的代码:

例 13. 实现您自己的 hashCode 
					
public int hashCode() {
 int result;
 result = (int) (id ^ (id >>> 32));
 result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
 result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
 result = 31 * result + (emailAddress != null ? emailAddress.hashCode() : 0);
 result = 31 * result + (creationDate != null ? creationDate.hashCode() : 0);
 return result;
}

不用说,这段代码也可以作为有效的 hashCode 方法,这两个 hashCode 方法您更愿意维护哪一个?哪一个更易于理解?还要注意,例 13 中如何利用三元操作符语句来避免大量的条件逻辑。您可能会想,Commons Lang 的 HashCodeBuilder 也许可以做类似的事情 — 但更好的是 Commons Lang 的开发人员在维护和测试它。
和 EqualsBuilder 一样,HashCodeBuilder 有另一个利用反射的 API。如果使用该 API,就不需要手动地用 append 方法添加基对象的每个属性,这样可以得到如例 14 所示的一个 hashCode 方法:

例 14. 使用 HashCodeBuilder 的反射 API
					
public int hashCode() {
 return HashCodeBuilder.reflectionHashCode(this);
}

和之前一样,由于这个方法在幕后应用 Java 反射,因此当进行安全性调整时,可能破坏该方法的功能,而且性能下降很多。

Apache Commons 项目运用 - toString篇

对象的字符串表示 Object 的 toString 方法的默认实现返回对象的完全限定名称,后面跟上一个 @ 字符,然后是对象的散列码的值。您可能早就明白,这对于区分不同的对象帮助不大。Commons...
  • KindAzrael
  • KindAzrael
  • 2012年03月29日 21:31
  • 1495

Apache Commons 项目运用 - Comparable篇

相对的 comparable 另一个有趣的方法也有一个相当正式的契约,那就是 Comparable 接口的 compareTo 方法。如果要控制特定的对象如何排序,那么这个接口非常重要。在本节中,您将...
  • KindAzrael
  • KindAzrael
  • 2012年03月30日 20:46
  • 1130

Apache Commons 项目运用 - equals篇

Commons Lang 是 Apache Commons 的一个组件,后者是一个宏大的项目,其中的很多子项目涉及到 Java? 语言软件开发的不同的方面。Commons Lang 扩展了标准 jav...
  • KindAzrael
  • KindAzrael
  • 2012年03月27日 00:28
  • 1672

Apache Commons项目介绍

Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动。 Commons BeanUtils 提供对Java反射和自省API的包装。 依赖包:Co...
  • accountwcx
  • accountwcx
  • 2014年09月02日 17:34
  • 2165

使用commons-lang.jar包以及反射机制实现javabean的equals,hashCode和toString三个方法重写

在实际项目中,有时需要对javabean的equals,hashCode和toString三个方法重写,一般情况下会选择手写,这样比较繁琐,另外一种方式是通过反射机制就可以完成,这样就显得更为简单。 ...
  • Thinkingcao
  • Thinkingcao
  • 2017年02月15日 14:40
  • 180

一篇关于apache commons类库的详解

Apache Commons类库 1.1. 开篇 在Java的世界,有很多(成千上万)开源的框架,有成功的,也有不那么成功的,有声名显赫的,也有默默无闻的。在我看来,成功而默默无闻的那些框架值得我...
  • yangwei19680827
  • yangwei19680827
  • 2014年04月12日 20:02
  • 7647

java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedObjectPoolFactory

今天实验dbcp时,出的错,用的jar包是 commons-dbcp-1.4.jar commons-pool2-2.4.1.jar commons-collections4-4.0.jar ...
  • birdofsky
  • birdofsky
  • 2015年07月24日 16:26
  • 2405

错误:java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils

废话不多,请仔细检查你的项目里是否缺少一下的一个或者多个包:xwork-core-2.3.4.jar,struts2-core-2.3.4.jar,ognl-3.0.5.jar,freemarker-...
  • hacker_Lees
  • hacker_Lees
  • 2017年06月21日 10:33
  • 1814

关于Spring中Commons Validator的使用说明

spring的validate验证需要两个bean(ValidatorFactory、BeanValidator)及两xml文件(validator-rules.xml、validation.xml)...
  • jamyy2000
  • jamyy2000
  • 2006年08月23日 15:08
  • 3406

apache-commons常用技术(一)

package com.j2se.base; import java.io.ByteArrayOutputStream; import java.io.IOException; import jav...
  • jintianhen1
  • jintianhen1
  • 2013年12月30日 15:16
  • 1260
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Apache Commons 项目运用 - hashCode篇
举报原因:
原因补充:

(最多只允许输入30个字)