黑马程序员技术交流社区

标题: 关于Map中hashCode的问题 [打印本页]

作者: 张豪杰    时间: 2013-2-25 16:06
标题: 关于Map中hashCode的问题
本帖最后由 张豪杰 于 2013-2-25 20:03 编辑

hashCode()方法可以提高Map里面的搜索效率的,Map会根据不同的hashCode()将数据存放在不同的区域,Map在搜索一个对象的时候先通过hashCode()找到相应的桶,然后再根据equals()方法找到相应的对象.要正确的实现Map里面查找元素必须满足一下两个条件:
(1)当obj1.equals(obj2)为true时obj1.hashCode()   ==   obj2.hashCode()为ture
(2)当obj1.hashCode()   !=   obj2.hashCode()为true时obj1.equals(obj2)也为ture。
上面第二点就疑惑了,为什么equals比较为true了,而hashCode的值为什么就不一定相等呢?
equals不是比较两个对象的内容么?而hashCode不是根据对象内容来产生一个值的么?这样的话,内容相同了,hashCode怎么会一样?
还是我对equals的理解错了?
作者: 张宁    时间: 2013-2-25 16:40
你看错了。。。你的理解是正确的
作者: 杨剑    时间: 2013-2-25 16:41
equals定义在Object类中,而Object类中的equals方法比较的是两个对象的地址值是否相等,每个类都会继承Object类,如果一个类没有重写equals方法,这个类的equals方法比较的是两个对象的地址是否相等,所以equals方法比较的有可能是地址值,有可能是内容,equals比较为true,如果比较的是内容,但是如果是两个对象,那么他们的hashCode就不一定相等,hash值指的是内存地址,两个对象的分配在内存中的不同地方,当然hashCode值不一样;重写hashcode()的方法的目的是让两个对象内容一致,认为是同一个对象。
作者: 刘治广    时间: 2013-2-25 16:42
应该是一个比较内容,一个比较指向的地址的吧
作者: 王钊    时间: 2013-2-25 16:43
第一句话是对的,第二句话有问题
我来介绍一个详细点的
首先,关于Object类的hashCode()方法的特点:
a) 在Java应用的一次执行过程当中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化)。
b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的
c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值要求一定不同(可以相同,可以不同),但是如果不同则可以提高应用的性能
d) 对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址)。
其次, 当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code值是否与增加的对象的hash code值一致;如果不一致,直接加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。
最后,如果我们重写equals方法,那么也要重写hashCode方法,反之亦然。

举个例子,比方说有两个“张三”长得一模一样(但毕竟不是同一个人equal为false),
假如他们住在同一个小区的同一个房子(hashCode相等),你去访问他们家,你进屋根本就分不清哪个是你找的“张三”
但是,如果他们一个住在北京一个住在上海(hashCode不同),你直接去你要找的"张三"的城市就能找到他了(提高了性能)。
作者: 谢洋    时间: 2013-2-25 17:56
hashCode不是根据对象内容来产生一个值的么?不是,是根据方法是如何运算的,
下面是示例代码可以长了点,拷到机上慢慢看吧
package test1;
/**
* 因为map的存储原理与hashset的是一样的,写了不同三个类来测方式结果
* Person1 没复写hashCode和equals方法
* Person2 复写hashCode和equals方法,hashcode方法返回结果固定不变
* Person3 复写hashCode和equals方法,
*/
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class HashMapTest {
public static void main(String[] args) {
  
  Collection set1 = new HashSet();
  
  set1.add(new Person1("zhang",23));
  set1.add(new Person1("zhang",23));
  set1.add(new Person1("zhang",23));
  System.out.println("set1:"+set1.size());
  
  Collection set2 = new HashSet();
  
  set2.add(new Person2("zhang",23));
  set2.add(new Person2("zhang",23));
  set2.add(new Person2("zhang",23));
  System.out.println("set2:"+set2.size());
  
  Collection set3 = new HashSet();
  
  set3.add(new Person3("zhang",23));
  set3.add(new Person3("zhang",23));
  set3.add(new Person3("zhang",23));
  System.out.println("set3:"+set3.size());
}
}
//该类不复写从Object继承来hashcode方法和equals方法,所以两个对象的hashcode不可以相同
class Person1{
private String name;
private int age;
public Person1(String name, int age) {
  super();
  this.name = name;
  this.age = age;
}
}
//该类复写从Object继承来hashcode方法和equals方法,但把返回的hashcode值固定,也就是说此类对象的返回hashcode值相同
class Person2{
private String name;
private int age;
public Person2(String name, int age) {
  super();
  this.name = name;
  this.age = age;
}
//复写hashCode();因为这个返值相同,还不能确定是否是同一个对象,所每次都会执行equals方法
@Override
public int hashCode() {
  return 60;
}
//复写equals方法
@Override
public boolean equals(Object obj) {
  System.out.println("Persen2的equals执行了");//测试每次操作是否都执行到这
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Person2 other = (Person2) obj;
  if (age != other.age)
   return false;
  if (name == null) {
   if (other.name != null)
    return false;
  } else if (!name.equals(other.name))
   return false;
  return true;
}
}
/**
* 该类复写从Object继承来hashcode方法和equals方法
* 类的成员变量(name和age)都参与这两个方法的返回结果的运算
*/
class Person3{
private String name;
private int age;
public Person3(String name, int age) {
  super();
  this.name = name;
  this.age = age;
}
//复写hashCode(),如果两个对象的name 和age都相等,则返回结果相同,这时会执行equals方法,否则认为是两个不同的对象,不会再执行equals方法
@Override
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + age;
  result = prime * result + ((name == null) ? 0 : name.hashCode());
  return result;
}
//复写equals方法,当则行到这,表明hashcode()返值相同,
@Override
public boolean equals(Object obj) {
  System.out.println("Persen3的equals执行了");//测试什么时候执行到这
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Person3 other = (Person3) obj;
  if (age != other.age)
   return false;
  if (name == null) {
   if (other.name != null)
    return false;
  } else if (!name.equals(other.name))
   return false;
  return true;
}
}







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2