`

HashCode和equal方法

    博客分类:
  • java
 
阅读更多

写的很好,源文:http://www.cnblogs.com/nktblog/articles/2518111.html

HashCode和equal方法

equals()反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。

而hashCode()是对象或变量通过哈希算法计算出的哈希值。

之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable。

 

两个obj,如果equals()相等,hashCode()一定相等。

两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。

所以:

可以考虑在集合中,判断两个对象是否相等的规则是:

第一步,如果hashCode()相等,则查看第二步,否则不相等;

第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

 

1、首先equals()和hashcode()这两个方法都是从object类中继承过来的。

equals()是对两个对象的地址值进行的比较(即比较引用是否相同)。

hashCode()是一个本地方法,它的实现是根据本地机器相关的。

2、Java语言对equals()的要求如下,这些要求是必须遵循的:

A 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

B 反射性:x.equals(x)必须返回是“true”。

C 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。

D 一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

3、equals()相等的两个对象,hashcode()一定相等;

反过来:hashcode()不等,一定能推出equals()也不等;

hashcode()相等,equals()可能相等,也可能不等。 

 

引用:http://blog.sina.com.cn/s/blog_59e0c16f0100xne7.html

1、为什么要重载equal方法?

答案:因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。

2、 为什么重载hashCode方法?

答案:一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode,那么为什么要重载hashCode呢?就HashMap来说,好比HashMap就是一个大内存块,里面有很多小内存块,小内存块里面是一系列的对象,可以利用hashCode来查找小内存块hashCode%size(小内存块数量),所以当equal相等时,hashCode必须相等,而且如果是object对象,必须重载hashCode和equal方法。

3、 为什么equals()相等,hashCode就一定要相等,而hashCode相等,却不要求equals相等?

答案:1、因为是按照hashCode来访问小内存块,所以hashCode必须相等。

2、HashMap获取一个对象是比较key的hashCode相等和equal为true。

之所以hashCode相等,却可以equal不等,就比如ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。

4、 为什么需要hashCode?

1、 通过hashCode可以很快的查到小内存块。
2、通过hashCode比较比equal方法快,当get时先比较hashCode,如果hashCode不同,直接返回false。

 

hashCode()的作用

1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0     1     2     3     4     5     6     7    
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除8求余数直接找到存放的位置了。

2.但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义   equals了。
也就是说,我们先通过   hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过   equals   来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊
3。你要对A类排序,有两种方法,一种就是让A类实现comparabole结构并实现compareTo()方法,那么可以通过Collections.sort(List    list)对其进行排序
另一种方法:自己定义一个类B实现Comparator类并实现compare方法,然后通过Collections.sort(List list,B b)进行排序

hashCode()是用来产生哈希玛的,而哈希玛是用来在散列存储结构中确定对象的存储地址的,(这一段在   Java编程思想   中讲的很清楚的)象util包中的带hash的集合类都是用这种存储结构:HashMap,HashSet, 他们在将对象存储时(严格说是对象引用),需要确定他们的地址吧,而HashCode()就是这个用途的,一般都需要重新定义它的,因为默认情况下,由 Object类定义的 hashCode 方法会针对不同的对象返回不同的整数,这一般是通过将该对象的内部地址转换成一个整数来实现的,现在举个例子来说,就拿HashSet来说   ,在将对象存入其中时,通过被存入对象的hashCode() 来确定对象在HashSet中的存储地址,通过equals()来确定存入的对象是否重复,hashCode() ,equals()都需要自己重新定义,因为hashCode()默认前面已经说啦,而equals()   默认是比较的对象引用,你现在想一下,如果你不定义equals()的话,那么同一个类产生的两个内容完全相同的对象都可以存入Set,因为他们是通过equals()来确定的,这样就使得HashSet失去了他的意义,看一下下面这个:
import java.util.*;

public class Test {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        for (int i = 0; i <= 3; i++){
            set.add(new Demo1(i,i));           
        }
        System.out.println(set);
        set.add(new Demo1(1,1));
        System.out.println(set);
        System.out.println(set.contains(new Demo1(0,0)));
        System.out.println(set.add(new Demo1(1,1)));
        System.out.println(set.add(new Demo1(4,4)));
        System.out.println(set);
    }

    private static class Demo1 {
        private int value;
       
        private int id;

        public Demo1(int value,int id) {
            this.value = value;
            this.id=id;
        }

        public String toString() {
            return " value = " + value;
        }

        public boolean equals(Object o) {
            Demo1 a = (Demo1) o;
            return (a.value == value) ? true : false;
        }

        public int hashCode() {
            return id;
        }
    }
}
你分别注释掉hashCode()和   equals()来比较一下他们作用就可以拉,关键要自己动手看看比较的结果你就可以记得很清楚啦

如果还不是很明确可以再看另一个例子:
import java.util.HashMap;
import java.util.Map;


public final class Test {

    public static void main(String[] args) {
        Map m = new HashMap();
        m.put(new PhoneNumber(020, 12345678), "shellfeng");
        System.out.println(m.get(new PhoneNumber(020, 12345678)));
    }

    private static class PhoneNumber {
       
        private short areaCode;

       
        private short extension;

        public PhoneNumber(int areaCode, int extension) {
            this.areaCode = (short) areaCode;
            this.extension = (short) extension;
        }

        public boolean equals(Object o) {
            if (o == this) {
                return true;
            }
            if (!(o instanceof PhoneNumber)) {
                return false;
            }
            PhoneNumber pn = (PhoneNumber) o;
            return pn.extension == extension && pn.areaCode == areaCode;
        }

       
        public int hashCode() {
            int result = 17;
            result = 37 * result + areaCode;
            result = 37 * result + extension;
            return result;
        }
    }
}

还是那句话:你注释掉hashCode()比较一下他们作用就可以拉,关键要自己动手看看比较的结果你就可以记得很清楚啦

总结
hashCode()方法使用来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的桶里面,Map在搜索一个对象的时候先通过hashCode()找到相应的桶,然后再根据equals()方法找到相应的对象.要正确的实现Map里面查找元素必须满足一下两个条件:
(1)当obj1.equals(obj2)为true时obj1.hashCode()   ==   obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时obj.equals(obj2)必须为false

Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。
但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。我们可以认为hashCode方法返回的就是对象存储的物理地址(实际可能并不是,例如:通过获取对象的物理地址然后除以8再求余,余数几是计算得到的散列值,我们就认为返回一个不是物理地址的数值,而是一个可以映射到物理地址的值)。
这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

分享到:
评论

相关推荐

    java中hashcode()和equals()方法详解

    在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...

    关于hashCode()和equals()的本质区别和联系

    Java 中的每个对象都有 hashCode() 和 equals() 方法,这两个方法的正确实现对于 Java 开发人员来说是非常重要的。本文将详细介绍 hashCode() 和 equals() 的本质区别和联系,并探讨在创建 Java 类时如何定义这些...

    Java中hashCode和equals方法的正确使用

    在这篇文章中,我将告诉大家我对hashCode和equals方法的理解。我将讨论他们的默认实现,以及如何正确的重写他们。我也将使用Apache Commons提供的工具包做一个实现。  hashCode()和equals()定义在Object类中,这...

    【面试】hashCode与equals两者之间的关系 / == 和equals / 为什么要重写equals方法 / 重写equals /hashcode方法 / 为什么要重写hashCode方法

    【面试】中提到的几个关键知识点集中在对象比较、equals()和hashCode()方法的使用以及它们之间的关系上。这些概念在Java编程中至关重要,特别是在处理集合类和比较对象时。 1、**hashCode与equals两者之间的关系**...

    Java中的hashcode方法介绍

    正确地重写`hashCode`和`equals`方法对于实现符合预期的行为至关重要,尤其是在自定义对象类中。这两个方法必须保持一致性:如果两个对象相等(`equals`返回`true`),那么它们的`hashCode`值必须相同。反之,如果`...

    string-hashcode:java.lang.String.hashCode

    字符串哈希码 字符串的其他实用程序。... equal ( code , code2 ) ;原料药hashCode(str)参数: str:字符串对象返回: 编号:哈希码返回字符串的哈希码。 请注意,哈希码对于特定字符串是不可变的。执照麻省理工学院

    面试官瞬间就饱了,重写equals函数,需要重写hashCode函数吗?

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是对象的基本组成部分,它们与对象的比较和哈希表(如 `HashMap`)的操作密切相关。在面试中,面试官提出的问题直指这两个方法的重要关联。 首先,`equals()` ...

    Findbugs缺陷等级对照表.pdf

    * 43B:类中定义了 hashCode() 方法,但是没有重写 java.lang.Object 中的 hashCode() 方法 * 44C:类中定义了 tostring() 方法,但是没有重写 java.lang.Object 中的 tostring() 方法 * 45C:某些方法名只有大小写...

    javaee_tedu_day09.zip

    ATM系统 Clone方法 toString方法:表示返回对象的字符串表示形式 包名.类名@hashCode(内存地址) 打印对象时,默认调用 如果不是想使用object类,toString...如果equal返回true的话,hashCode相同,重写hashCode方法

    Java中equals()与hashCode()的原理与设计

    1、何时需要重写equals() ...  如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。  简单的说,“相等的对象必须具有相等的散列码”。  3、什么是equals()与如何设计equals()

    java中重写equals和重写hashCode()

    在Java编程语言中,`equals()` 和 `hashCode()` 是两个非常重要的方法,它们主要用于比较对象的平等性以及在散列数据结构(如 `HashMap`、`HashSet` 等)中的对象定位。当我们创建自定义类时,有时需要根据业务需求...

    Java-Reflection-and-Object-Comparison-in-Java:Java Reflection创建适当的对象,覆盖equal和hashCode方法

    Java中的Java反射和对象比较 项目介绍 首先,通过以下方式设计Java类: 2个私有数据成员int IntValue; 字符串StringValue; 空构造函数定义公共方法void setIntValue(int iIn){...}定义公共方法void ...

    Java equals 方法与hashcode 方法的深入解析

    PS:本文使用jdk1.7解析1.Object类 的equals 方法 代码如下: /** * Indicates whether some other object is “equal to” this one. *  * The {@code equals} method implements an equivalence relation * on ...

    8张图解java.docx

    equals() 方法和 hashCode() 方法是 Object 类中的两个重要方法。equals() 方法用于比较两个对象是否相等,而 hashCode() 方法用于返回对象的哈希值。它们的区别在于: * 如果两个对象相等(equal),那么他们一定...

    八张图深度理解Java特性

    equals() 方法和 hashCode() 方法是 Java 中两个非常重要的方法,它们的作用是分别比较两个对象的值和哈希值。图 2 展示了这两个方法的区别: * 如果两个对象相等(equal),那么他们一定有相同的哈希值。 * 如果两...

    HashSet和TreeSet使用方法的区别解析

    在使用HashSet和TreeSet时,需要注意hashCode()和equal()方法的实现。hashCode()方法用于计算元素的哈希值,equal()方法用于比较元素的相等性。在覆写这些方法时,需要注意不要把它们和可变属性关联上,否则可能会...

    java个人总结.docx

    在这个个人总结中,我们将探讨几个关键的Java知识点,包括对象创建、equals与hashCode方法、对象序列化以及String、StringBuffer和StringBuilder的区别。 首先,让我们来看看创建Java对象的四种方式: 1. **New**...

    java中 == 与 equal 的区别讲解

    同时,为了保持哈希表的正确性,重写 `equals()` 时通常也需要重写 `hashCode()` 方法。 ```java @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || ...

    学生集合排序

    本文将详细探讨如何实现这个过程,重点在于重写`hashCode`和`equals`方法,以及利用`Collections`工具类和自定义比较器来实现多属性排序。 首先,让我们了解`hashCode`和`equals`方法的重要性。这两个方法是Java中...

    关于重写equals()为什么一定要重写hashcode()自己的一点心得

    首先我们看下下面代码及输出和String重写equals和hashcode的源码: package com.zzy.test; public class Test6 { public static void main(String[] args) { String s1="aaa"; String s2="aaa"; String s3=new ...

Global site tag (gtag.js) - Google Analytics