基础知识-hashcode()和equals()

hashCode()方法被用来获取给定对象的惟一整数,这个整数被用来肯定对象被存储在HashTable相似的结构中的位置,Object类的hashCode()方法返回这个对象存储的内存地址的编号。java

equal()相等的两个对象他们的hashCode()确定相等 
hashCode()相等的两个对象他们的equal()不必定相等

对比的时候算法

首先用hashCode()去对比,若是hashCode()不同,则表示这两个对象确定不相等   
若是hashCode()相同,此时再对比他们的equal(),若是equal()也相同,则表示这两个对象是真的相同了

这样的好处apache

hash散列算法,使得在hash表中查找一个记录速度变O(1).每一个记录都有本身的hashcode,散列算法按照hashcode把记录放置在合适的位置.在查找一个记录,首先先经过hashcode快速定位记录的位置.而后再经过equals来比较是否相等.没有hashcode,一个一个比较过来,时间就变O(N)了

这种大量的而且快速的对象对比通常使用的hash容器中,好比hashset,hashmap,hashtable等等,好比hashset里要求对象不能重复,则他内部必然要对添加进去的每一个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),若是hashCode()相同,再用equal()验证,若是hashCode()都不一样,则确定不一样,这样对比的效率就很高了app

然而hashCode()和equal()同样都是基本类Object里的方法,而和equal()同样,Object里hashCode()里面只是返回当前对象的地址,若是是这样的话,那么咱们相同的一个类,new两个对象,因为他们在内存里的地址不一样,则他们的hashCode()不一样,因此这显然不是咱们想要的,因此咱们必须重写咱们类的hashCode()方法ide

public class Employee
{
    private Integer id;
    private String firstname;
    private String lastName;
    private String department;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getDepartment() {
        return department;
    }
    public void setDepartment(String department) {
        this.department = department;
    }
}
public class EqualsTest {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);
        //Prints false in console
        System.out.println(e1.equals(e2));
    }
}

毫无疑问,上面的程序将输出false
咱们须要重写equals方法ui

public boolean equals(Object o) {
        if(o == null)
        {
            return false;
        }
        if (o == this)
        {
           return true;
        }
        if (getClass() != o.getClass())
        {
            return false;
        }
        Employee e = (Employee) o;
        return (this.getId() == e.getId());
}

在上面的类中添加这个方法,EauqlsTest将会输出true。this

import java.util.HashSet;
import java.util.Set;

public class EqualsTest
{
    public static void main(String[] args)
    {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);

        //Prints 'true'
        System.out.println(e1.equals(e2));

        Set<Employee> employees = new HashSet<Employee>();
        employees.add(e1);
        employees.add(e2);
        //Prints two objects
        System.out.println(employees);
    }
}

上面的程序输出的结果是两个。若是两个employee对象equals返回true,Set中应该只存储一个对象才对,问题在哪里呢?
咱们忘掉了第二个重要的方法hashCode()。就像JDK的Javadoc中所说的同样,若是重写equals()方法必需要重写hashCode()方法。咱们加上下面这个方法,程序将执行正确。.net

@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }

使用Apache Commons Lang包重写hashCode() 和equals()方法
Apache Commons 包提供了两个很是优秀的类来生成hashCode()和equals()方法。看下面的程序。code

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
 private Integer id;
 private String firstname;
 private String lastName;
 private String department;
public Integer getId() {
    return id;
 }
 public void setId(Integer id) {
    this.id = id;
 }
 public String getFirstname() {
    return firstname;
 }
 public void setFirstname(String firstname) {
    this.firstname = firstname;
 }
 public String getLastName() {
    return lastName;
 }
 public void setLastName(String lastName) {
    this.lastName = lastName;
 }
 public String getDepartment() {
    return department;
 }
 public void setDepartment(String department) {
    this.department = department;
 }
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
           toHashCode();
 }
@Override
 public boolean equals(Object o) {
    if (o == null)
       return false;
    if (o == this)
       return true;
    if (o.getClass() != getClass())
       return false;
    Employee e = (Employee) o;
       return new EqualsBuilder().
              append(getId(), e.getId()).
              isEquals();
    }
 }

若是你使用Eclipse或者其余的IDE,IDE也可能会提供生成良好的hashCode()方法和equals()方法。 对象

须要注意记住的事情

尽可能保证使用对象的同一个属性来生成hashCode()和equals()两个方法。在咱们的案例中,咱们使用员工id。
eqauls方法必须保证一致(若是对象没有被修改,equals应该返回相同的值)
任什么时候候只要a.equals(b),那么a.hashCode()必须和b.hashCode()相等。
二者必须同时重写。
当使用ORM的时候特别要注意的
若是你使用ORM处理一些对象的话,你要确保在hashCode()和equals()对象中使用getter和setter而不是直接引用成员变量。由于在ORM中有的时候成员变量会被延时加载,这些变量只有当getter方法被调用的时候才真正可用。
例如在咱们的例子中,若是咱们使用e1.id == e2.id则可能会出现这个问题,可是咱们使用e1.getId() == e2.getId()就不会出现这个问题。

文章引用:https://www.oschina.net/quest...

相关文章
相关标签/搜索