天天看點

hashcode、equals和==

參考:http://blog.csdn.net/hzw19920329/article/details/51944114

1、equals和==

equals的作用是用來判斷兩個對象是否相等,Java中所有的類都實作了equals方法。在equals沒有被重寫的情況下equals等價于==

==比較(這裡指對象比較)的是兩個對象是否是同一個對象

public class User {
    private String username;
    private String pass;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public User(String username, String pass) {
        super();
        this.username = username;
        this.pass = pass;
    }   
}   
           

用==測試

public static void main(String[] args) {
        User u1=new User("vivien","1234");
        User u2=new User("vivien","1234");
        System.out.println(u1==u2);
        System.out.println(u1.equals(u2));
        }
           

輸出

false

false

盡管變量都一樣,但是這兩個畢竟不是同一個對象,是以執行==時顯示false,而在沒有重寫equals的時候equals等價于==(String預設是重寫了equals的,是以執行equals的時候new兩個一樣的String用equals比較是true)

重寫equals:

public class User {
    private String username;
    private String pass;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public User(String username, String pass) {
        super();
        this.username = username;
        this.pass = pass;
    }   
        @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj==null)
            return false;
        if(obj==this)
            return true;
        if(obj instanceof User)
        {
            User o=(User)obj;
            if(o.getUsername()==this.username && o.getPass()==this.pass)
                return true;
            else return false;  
        }
        else
        {
            return false;
        }
    }
}
           

重新測試顯示:

false

true

可以發現重寫了equals之後輸出true

注意equals原則:

1. 對稱性:如果x.equals(y)傳回是”true”,那麼y.equals(x)也應該傳回是”true”。

2. 反射性:x.equals(x)必須傳回是”true”。

3. 類推性:如果x.equals(y)傳回是”true”,而且y.equals(z)傳回是”true”,那麼z.equals(x)也應該傳回是”true”。

4. 一緻性:如果x.equals(y)傳回是”true”,隻要x和y内容一直不變,不管你重複x.equals(y)多少次,傳回都是”true”。

5. 非空性,x.equals(null),永遠傳回是”false”;x.equals(和x不同類型的對象)永遠傳回是”false”。

2、equals和hashCode()

hashCode()的作用是擷取哈希碼,也稱為散列碼,傳回的是一個int整數。

這兩個如果不是在散清單中比較完全沒有意思。因為如果這個類不是放在散清單中,equals和hashCode()沒有半毛錢關系。

這裡我以hashMap來說兩者關系吧

HashMap解決沖突的方法時拉鍊法(把所有hashCode相同的鍵值對用單連結清單連接配接起來),這也導緻了HahMap的結構–數組+連結清單:

hashcode、equals和==

每個鍵值對在hashMap中是以Entry的形式存在

HashMap的put原理:

首先用hashCode()方法計算目前key的hash值,接着找到計算出來的hash值在數組中的下标位置,檢視該下标位置處對應的連結清單是否為null,為null的話直接将目前鍵值對插入到該連結清單首位。如果下标位置處對應的連結清單不為null的話,會使用for循環,每次循環通過key的equals()方法檢視這個連結清單中有沒有與目前鍵值對相等的Entry存在,有的話會用目前值替換原先這個鍵值對的value值,周遊結束如果不存在的話,會将目前鍵值對插入到連結清單頭部。

HashMap的get原理

get操作過程思想可以借助于put過程,首先會計算出目前key值的hash值,接着找到此hash值在數組中的位置,找到這個位置對應的連結清單,接着通過for循環周遊這個連結清單,周遊過程中調用equals方法檢視有沒有等于目前key的鍵值對存在,有的話直接傳回這個鍵值對對應的value值即可

是以HashMap 如果想要實作讓對象做key,并且相同變量的對象視為相同的key的話,一定要重寫equals()方法和hashCode()方法。什麼意思呢,直接看例子:

上面的User類如果我沒有重寫equals()方法和hashCode()方法,把User類作為key,存到HashMap中時:

public static void main(String[] args) {
        Map<User,String> m=new HashMap<User,String>();
        User u1=new User("vivien","1234");
        User u2=new User("vivien","1234");
        m.put(u1, "這是u1");
        m.put(u2, "這是u2");
        System.out.println("u1 hashCode():"+u1.hashCode());
        System.out.println("u2 hashCode():"+u2.hashCode());
        System.out.println("u1.equals(u2)?"+u1.equals(u2));
        Set<Map.Entry<User, String>> entries=m.entrySet();
        Iterator it=entries.iterator();
        while(it.hasNext())
            System.out.println(it.next());
    }
           

輸出(為了輸出直覺,為在User中重寫了toString()方法):

u1 hashCode():1704856573

u2 hashCode():705927765

u1.equals(u2)?false

User [username=vivien, pass=1234]=這是u1

User [username=vivien, pass=1234]=這是u2

很顯然,u1和u2hashCode不一樣,并且也不equals,HashMap把u1和u2當做兩個key來對待

現在重寫equals和hashCode()方法:

public class User {
    private String username;
    private String pass;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }

    @Override
    public String toString() {
        return "User [username=" + username + ", pass=" + pass
                + "]";
    }
    public User(String username, String pass) {
        super();
        this.username = username;
        this.pass = pass;
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj==null)
            return false;
        if(obj==this)
            return true;
        if(obj instanceof User)
        {
            User o=(User)obj;
            if(o.getUsername()==this.username && o.getPass()==this.pass)
                return true;
            else return false;  
        }
        else
        {
            return false;
        }
    }
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return (this.username+this.pass).hashCode();
    }
}   
           

重新運作上面的test:

u1 hashCode():-1331478383

u2 hashCode():-1331478383

u1.equals(u2)?true

User [username=vivien, pass=1234]=這是u2

這時可以看到,在插入u2時,HashMap首先計算u2 hashCode,找到了與u1相同hashCode的鍊,在這個鍊中,通過for循環發現u1的key equals u2的key,是以把u2對應的value覆寫u1對應的value。是以最後周遊Map發現隻有一個鍵值對