改写hashCode()

        改写equals时总是要改写hashCode java.lang.Object中对hashCode的约定:
  在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
  如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
  如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
        看个不改写hashCode导致使用hashMap不能出现预期结果的例子:
  public final class PhoneNumber{
  private final short areaCode;
  private final short exchange;
  private final short extension;
  public PhoneNumber(int areaCode,int exchage,int extension){
  rangeCheck(areaCode,999,"area code");
  rangeCheck(exchange,999,"exchange");
  rangeCheck(extension,9999,"extension");
  this.areaCode=(short) areaCode;
  this.exchange=(short) exchange;
  this.extension=(short)extension;
  }
  private static void rangeCheck(int arg,int max, String name){
  if(arg<0 || arg>max) throw new IllegalArgumentException(name+":"+arg);
  }
  public boolean equals(Object o){
  if (o == this) reutrn true;
  if (!(o instanceof PhoneNumber)) return false;
  PhoneNumber pn=(PhoneNumber)o;
  return pn.extension==extension &&pn.exchange=exchange &&pn.areaCode=areaCode;
  }
  //No hashCode method
  ...
  }
  现在有以下几行程序:
  Map m=new HashMap();
  m.put(new PhoneNumber(1,2,3),"Jenny");
  则m.get(new PhoneNumber(1,2,3))的返回值什么?
    虽然这个实例据equals是相等的,但由于没改写hashCode而致两个实例的散列码并不同(即违反第二条要求),因则返回的结果是null而不是"Jenny".
    理想情况下,一个散列函数应该把一个集合中不相等的实例均匀地分布到所有可能的散列值上,下面是接近理想的“处方”:
  把某个非零常数值(如17)保存在一个叫result的int类型的变量中;
  对于对象中每个关键字域f(指equals方法中考虑的每一个域),完成以下步骤:
  为该域计算int类型的散列码c:
  如果该域是bloolean类型,则计算(f?0:1)
  如果该域是byte,char,short或int类型,则计算(int)f
  如果该域是long类型,则计算(int)(f^(>>>32))
  如果该域是float类型,则计算Float.floatToIntBits(f)
  如果该域是double类型,则计算Double.doubleToLongBits(f)得一long类型值,然后按前述计算此long类型的散列值
  如果该域是一个对象引用,则利用此对象的hashCode,如果域的值为null,则返回0
  如果该域是一个数组,则对每一个数组元素当作单独的域来处理,然后安下一步的方案来进行合成
  利用下面的公式将散列码c 组合到result中。result=37*result+c;
  检查“相等的实例是否具有相等的散列码?”,如果为否,则修正错误。
    依照这个处方,得PhoneNumber的hashCode方法:
  public int hashCode(){
  int result=17;
  result=37*result+areaCode;
  result=37*result+exchange;
  result=37*result+extension;
  return result;
  }
    如果计算散列码的代价比较高,可以考虑用内部保存这个码,在创建是生成或迟缓初始化生成它。不要试图从散列码计算中排除掉一个对象的关键部分以提高性能。
        本文转自
http://lift.blogdriver.com/lift/475611.html   
key的hashcodeequals方法改写 在第一部分hashmap的数据结构中,annegu就写了get方法的过程:首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。所以,hashcodeequals方法对于找到对应元素是两个关键方法。 Hashmap的key可以是任何类型的对象,例如User这种对象,为了保证两个具有相同属性的user的hashcode相同,我们就需要改写hashcode方法,比方把hashcode值的计算与User对象的id关联起来,那么只要user对象拥有相同id,那么他们的hashcode也能保持一致了,这样就可以找到在hashmap数组中的位置了。如果这个位置上有多个元素,还需要用key的equals方法在对应位置的链表中找到需要的元素,所以只改写hashcode方法是不够的,equals方法也是需要改写滴~当然啦,按正常思维逻辑,equals方法一般都会根据实际的业务内容来定义,例如根据user对象的id来判断两个user是否相等。 在改写equals方法的时候,需要满足以下三点: (1) 自反性:就是说a.equals(a)必须为true。 (2) 对称性:就是说a.equals(b)=true的话,b.equals(a)也必须为true。 (3) 传递性:就是说a.equals(b)=true,并且b.equals(c)=true的话,a.equals(c)也必须为true。 通过改写key对象的equalshashcode方法,我们可以将任意的业务对象作为map的key(前提是你确实有这样的需要)。
10-31
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值