A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

往HashMap集合中,加入对象
为保证键的唯一性

为什么要重写hashCode() 和equals()方法。


public int hashCode()
{
      //为什么这样写
       return name.hashCode()+age*34;
}

public boolean equals(Object obj)
{
    //为什么这样写
     if(!(obj instanceof Person))
      return false;
     Person  p = (Person)obj;
     //如果姓名和年龄相同
      return this.name.equals(p.name)&&this.age == p.age;
  
}

为什么要重写hashCode() 和equals()方法。

评分

参与人数 1黑马币 +3 收起 理由
张_涛 + 3

查看全部评分

4 个回复

倒序浏览
public int hashCode()返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。  
hashCode 的常规协定是:  

在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。  
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。  
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。  
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

public boolean equals(Object obj)指示某个其他对象是否与此对象“相等”。  
equals 方法在非空对象引用上实现相等关系:  

自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。  
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。  
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。  
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。  
对于任何非空引用值 x,x.equals(null) 都应返回 false。  
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。  

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。  


参数:
obj - 要与之比较的引用对象。  
返回:
如果此对象与 obj 参数相同,则返回 true;否则返回 false。


希望我的答案对你有用

评分

参与人数 1技术分 +1 收起 理由
张_涛 + 1 赞一个!

查看全部评分

回复 使用道具 举报
  首先,根据API文档这两个方法都来自于Object对象
  如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等
但是,一般比较地址是否相等,没有意义。所以,我们重写这个方法,按照我们自己的要求来实现自己的比较。
   hashCode 是返回该对象的哈希码值

比如:有个学生类 比较是不是同一个学生
class Student
{
        private int age;

        Student(){}

        Student(int age)
        {
                this.age = age;
        }

        public void setAge(int age)
        {
                this.age = age;
        }

        public int getAge()
        {
                return age;
        }

        //重写toString方法
        public String toString()
        {
                return "age:"+age;
        }

        //比较两个学生的年纪是否相等
        /*
        public boolean compare(Student s)
        {
                return this.age == s.age;
        }
        */
        //这个时候,由于Student类本身继承了Object,它就具有了equals方法。
        //这个方法也是用于比较的,看起来功能很类似,所以,
        //我就不用再起其他的方法名字完成比较学生的年纪是否相等
        //直接用equals方法即可。
        public boolean equals(Object obj)  //Object obj = s2;  s2 = new Student(); 向上转型。多态
        {
                //return this.age == s.age;
                //return this.age == obj.age;

                //为了提高程序的效率
                if(this == obj)    //判断是不是其本身 如果是本身 肯定为true
                {
                        //System.out.println("haha");
                        return true;
                }

                //为了程序的健壮性
                if(!(obj instanceof Student))  //判断传的是不是同一类型
                {
                        return false;
                }

                //向下转型
                Student s = (Student)obj;//因为传入的时候已经向上转型了,所以要强制为Student类型
                return this.age == s.age;
        }
}

class ObjectDemo2
{
        public static void main(String[] args)
        {
                Student s1 = new Student();
                System.out.println(s1);

                Student s2 = new Student(20);
                System.out.println(s2);

                Student s3 = new Student(20);
                System.out.println(s3);

                //System.out.println(s2==s3);
                //equals方法用于比较对象的地址值是否相等
                System.out.println(s2.equals(s3));  //false

                //比较对象的年纪
                //System.out.println(s1.compare(s2)); //false
                //System.out.println(s2.compare(s3)); //true

                System.out.println(s1.equals(s2));
                System.out.println(s2.equals(s3));

                //可能的问题
                System.out.println(s2.equals(s2));
                ObjectDemo2 obj2 = new ObjectDemo2();
                //ClassCastException
                System.out.println(s2.equals(obj2));
        }
}

评分

参与人数 1技术分 +1 收起 理由
张_涛 + 1 赞一个!

查看全部评分

回复 使用道具 举报
HashMap中的键是唯一的,它确定键的唯一性是通过hashCode()和equals()方法确定的。
当该集合的对象调用put()时,会调用该对象的hashcode()方法,
如果返回的哈希值在该HashMap集合中键对应的哈希值中不存在,则调用equals()方法,当equals()方法返回true时,存入,否则存入失败;
如果返回的哈希值在该HashMap集合中键对应的哈希值中存在,则不调用equals()方法,直接存入失败。
Object类的equals和hashcode方法是比较内存地址,如果双方具有相同内存地址,则equals和hashcode都相同。
重写hashcode()目的是使相同的对象具有相同的哈希值。如果按上面代码中重写hashcode的算法,大概能保证相同的对象具有相同的哈希值,不同的对象具有不同的哈希值。为确保键确实唯一,需要重写equals方法再验证一次两个对象的name和age是否相等。
这样,用hashcode()和equals()两个维度确保如果是相同的对象,就不会存放了。

评分

参与人数 1技术分 +1 收起 理由
张_涛 + 1 赞一个!

查看全部评分

回复 使用道具 举报
  在一个集合中,如果要查找某个对象,大概的代码会怎么写呢?通常是逐一取出每个元素与要查找的元素进行比较,当发现某个元素与要查找的对象进行equals方法进行比较的结果相等时,则停止继续查找并返回肯定的信息,否则返回否定的信息。但如果一个集合中有很多元素,则意味着你的程序可能要从很多个元素逐一取出才能得出结论。
   于是便有了哈希算法,用这种算法将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域。
   HashMap就是采用哈希算法存取对象的集合,当从HashMap中查找某个对象时,java系统首先调用对象的hashCode()方法获得该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素与该对象进行equals方法比较,这样不用遍历集合中的所有元素就可以得到结论。
   为了保证一个类的实例对象能在HashMap正常存储,要求这个类的两个实例对象用equals()方法比较的结果相等时,它们的哈希码也必须相等。如果一个类的hashCode()方法没有遵循上述要求,那么,当这个类的两个实例对象用equals()方法比较的结果相等时,他们本来应该无法被同时存储进Map集合中,但是,如果由于它们的hashCode()的返回值不同,第二个对象首先按哈希码计算可能会被放进与第一个对象不同的区域中,这样,它就不可能与第一个对象进行equals方法比较了,也就可能被存储进HashMap中了。Object类中的hashCode()方法不能满足要求,因为它的返回值是通过对象的内存地址推算出来的,同一个对象在程序运行期间哈希值都是始终不变的。所以,只要是两个对象,即使它们的equals方法比较结果相等,它们默认的hashCode方法的返回值是不同的。所以必须重写hashCode()方法。并且我们重写的返回值要尽量每个对象都不同,这样就不用再调用equals了,更加效率。
重写equals可以自定义判断什么情况下两个对象是相同的。所以一般都是要重写的。

评分

参与人数 1技术分 +1 收起 理由
张_涛 + 1 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马