基礎知識-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...

相關文章
相關標籤/搜索