Java---hashCode()和equals()

Posted zhuweiheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java---hashCode()和equals()相关的知识,希望对你有一定的参考价值。

1.hashCode()和equals() API

hashCode()和equals()都来自上帝类Object, 所有的类都会拥有这两个方法,特定时,复写它们。

它们是用来在同一类中做比较用的,尤其是在容器里如Set存放同一类对象时用来判断放入的对象是否重复。

下面是API中的介绍:

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 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

int hashCode () :返回对象的哈希码值。                                                                                                                           

支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

hashCode 的常规协定是:

在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。

从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
如果根据
equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

要点:

(1)equals()相等的两个对象,hashcode()一定相等,equals()不相等的两个对象,却并不能证明它们的hashcode()不相等;

    equals()方法不相等的两个对象,hashCode()有可能相等。

(2)hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

(3)在object类中,hashcode()方法是本地方法,返回的是本对象(单一对象)的地址值;而object类中的equals()方法比较的 

    也是两个对象的地址值。如果equals()相等,说明两个对象地址值也相等,hashcode()也就相等。

(4)当我们重写一个对象的equals方法,通常有必要重写它的hashCode方法。以维护 hashCode 方法的常规协定 


equals()与==的比较

(1)‘==‘是用来比较两个变量(基本类型和对象类型)的值是否相等的。 如果两个变量是基本类型的,直接比较值就可以了。如果两个变量是对象类型的,比较的是这两个对象在栈中的引用(即地址)。

对象是放在堆中的,栈中存放的是对象的引用(地址)。由此可见‘==‘是比较栈中的值。如果要比较堆中对象的内容是否相同,那么就要重写equals方法了
(2)Object类中的equals方法就是用‘==‘来比较的,所以如果没有重写equals方法,equals和==是等价的。

通常我们会重写equals方法,让equals比较两个对象的属性内容,而不是比较对象的引用(地址),因为往往我们觉得比较对象的内容是否相同比比较对象的引用(地址)更有意义。


2.HashCode的作用

数据结构---哈希表中简单介绍了散列表的原理,一句话就是:hash算法提高了查找元素的效率。

如何查找一个集合中是否包含有某个对象呢?

一种方法是逐一取出每个元素与要查找的对象,使用equals方法比较的是否相等。如果一个集合中有很多个元素,则效率很慢。

哈希算法的思想:HashCode应该就和使用拼音查询汉字相似(建立拼音索引),这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将HashCode分组,每组分别对应某个存储区域,根据一个对象的HashCode就可以确定该对象应该存储在哪个区域。

Object类中定义了一个hashCode()方法来返回每个Java对象的HashCode,当从Set集合中查找某个对象时,Java系统首先调用对象的hashCode()方法获得该对象的hashCode表,然后根据hashCode找到相应的存储区域,最后取得该存储区域内的每个元素与该对象进行equals方法比较。这样就不用遍历所有对象,提高效率。

技术分享图片

HashCode在Java容器中的应用

对于List集合、数组而言,HashCode不重要,但是对于HashMap、HashSet、HashTable等而言,它变得异常重要。所以在使用HashMap、HashSet、HashTable时一定要注意hashCode。对于一个对象而言,其hashCode过程就是一个简单的Hash算法的实现,其实现过程对你实现对象的存取过程起到非常重要的作用。

一个对象肯定存在若干个属性,如何选择属性实现均匀散列(哈希表也称为散列表,其要保持尽可能均匀,不重复),考验着一个人的设计能力。

如果我们将所有属性进行散列,这必定会是一个糟糕的设计,因为对象的hashCode方法无时无刻不是在被调用,如果太多的属性参与散列,那么需要的操作数时间将会大大增加,这将严重影响程序的性能。

如果较少属相参与散列,散列的多样性会削弱,会产生大量的散列“冲突或碰撞”,除了不能够很好的利用空间外,在某种程度也会影响对象的查询效率。其实这两者是一个矛盾体,散列的多样性会带来性能的降低。

3.复写(@Override)hashCode()和equals() 的栗子

public class Employee implements Comparable<Employee> {

    private String name;
    private int age;
    
    
    public Employee() {
        super();
        
    }
    
    public Employee(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Emplooye [name=" + name + ", age=" + age + "]";
    }

    @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;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) 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;
    }

    @Override
    public int compareTo(Employee o) {
        
        int temp = this.age - o.age;
        return temp==0? this.name.compareTo(o.name):temp;
    }
    
}

技术分享图片

2018-01-07








以上是关于Java---hashCode()和equals()的主要内容,如果未能解决你的问题,请参考以下文章

Java hashCode() 和 equals()的若干问题解答

Java---hashCode()和equals()

Java hashCode() 和 equals()的若干问题解答

java hashCode, 引用以及equals().

3.Java hashCode() equals总结

Java hashCode与equals学习