1. 程式人生 > >昨天面試面到equals()和hashCode()關係了

昨天面試面到equals()和hashCode()關係了

equals()和hashCode()方法是用來在同一類中做比較用的,尤其是在容器裡如set存放同一類物件時用來判斷放入的物件是否重複。

先說重點:針對筆試

  equals()相等的兩個物件,hashcode()一定相等,equals()不相等的兩個物件,卻並不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個物件,hashCode()有可能相等。(我的理解是由於雜湊碼在生成的時候產生衝突造成的)

反過來:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。在object類中,hashcode()方法是本地方法,返回的是物件的地址值,而object類中的equals()方法比較的也是兩個物件的地址值,如果equals()相等,說明兩個物件地址值也相等,當然hashcode() 也就相等了;

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

原理:

equals方法的呼叫

預設情況(沒有覆蓋equals方法)下equals方法都是呼叫Object類的equals方法,而Object的equals方法主要用於判斷物件的記憶體地址引用是不是同一個地址(是不是同一個物件)。

要是類中覆蓋了equals方法,那麼就要根據具體的程式碼來確定equals方法的作用了,覆蓋後一般都是通過物件的內容是否相等來判斷物件是否相等。

class Student {  
    private int age;  
    private String name;  
      
    public Student() {  
    }  
    public Student(int age, String name) {  
        super();  
        this.age = age;  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  

public class EqualsTest {  
    public static void main(String[] args) {  
        LinkedList<Student> list = new LinkedList<Student>();  
        Set<Student> set = new HashSet<Student>();  
        Student stu1  = new Student(3,"張三");  
        Student stu2  = new Student(3,"張三");  
        System.out.println("stu1 == stu2 : "+(stu1 == stu2));  
        System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));  
        list.add(stu1);  
        list.add(stu2);  
        System.out.println("list size:"+ list.size());  
          
        set.add(stu1);  
        set.add(stu2);  
        System.out.println("set size:"+ set.size());  
    }  
  
}  

執行結果:

stu1 == stu2 : false
stu1.equals(stu2) : false
list size:2
set size:2

結果分析:Student類沒有覆蓋equals方法,stu1呼叫equals方法實際上呼叫的是Object的equals方法。所以採用物件記憶體地址是否相等來判斷物件是否相等。因為是兩個新物件所以物件的記憶體地址不相等,所以stu1.equals(stu2) 是false。

覆蓋一下equals方法(age和name屬性),讓Student類其通過判斷物件的內容是否相等來確定物件是否相等。

class Student {  
    private int age;  
    private String name;  
      
    public Student() {  
    }  
    public Student(int age, String name) {  
        super();  
        this.age = age;  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
   <span style="background-color: rgb(255, 255, 204);"> @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        Student other = (Student) 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;  
    }  </span>
      
}  
執行結果:

stu1 == stu2 : false
stu1.equals(stu2) : true
list size:2
set size:2

結果分析:因為Student兩個物件的age和name屬性相等,而且又是通過覆蓋equals方法來判斷的,所示stu1.equals(stu2) 為true。注意以上幾次測試list和set的size都是2

HashCode方法的呼叫

通過以上的程式碼執行,我們知道equals方法已經生效。接下來我們在覆蓋一下hashCode方法(通過age和name屬性來生成hashcode)並不覆蓋equals方法,其中Hash碼是通過age和name生成的。

class Student {  
    private int age;  
    private String name;  
      
    public Student() {  
    }  
    public Student(int age, String name) {  
        super();  
        this.age = age;  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    @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;  
    }     
}  

執行結果:

stu1 == stu2 : false
stu1.equals(stu2) : false
list size:2
hashCode :775943
hashCode :775943
set size:2

結果分析:我們並沒有覆蓋equals方法只覆蓋了hashCode方法,兩個物件雖然hashCode一樣,但在將stu1和stu2放入set集合時由於equals方法比較的兩個物件是false,所以就沒有在比較兩個物件的hashcode值。

我們覆蓋一下equals方法和hashCode方法。

 class Student {  
    private int age;  
    private String name;  
    public Student() {  
    }  
    public Student(int age, String name) {  
        super();  
        this.age = age;  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    @Override  
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + age;  
        result = prime * result + ((name == null) ? 0 : name.hashCode());  
        System.out.println("hashCode : "+ result);  
        return result;  
    }  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        Student other = (Student) 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;  
    }  
      
}  

執行結果:

stu1 == stu2 : false

stu1.equals(stu2) :true

list size:2

hashCode :775943

hashCode :775943

set size:1

結果分析:stu1和stu2通過equals方法比較相等,而且返回的hashCode值一樣,所以放入set集合中時只放入了一個物件。