面試官讓你說說==和equals()的區別,重寫equals必須重寫hashcode方法嗎

面試官讓你說說==和equals()的區別,重寫equals必須重寫hashcode方法嗎

  • 自己特質來講java

    • ==:操做符
    • equals():方法
  • 適用對象面試

    • ==:主要用於基本類型之間的比較(char、Boolean、byte、short、int、long、float、dobule),也能夠用於比較對象
    • equals():對象之間的比較(基本類型的包裝器類型,string,本身定義的對象等)
  • 比較對象時的區別數組

    • ==:比較兩個對象是否指向同一個對象,也就是說他們指向的對象的首地址是否相同
    • equals():能夠經過重寫equals方法從而比較對象的內容是否相同,若是不重寫那麼和==符號沒有區別,都是比較的對象的引用是否指向同一個對象

對於一個對象student來講,若是咱們不重寫它的equals方法,那麼和==符號同樣比較的是對象的引用而不是內容ide

public class Student {
    private int id;
    private String name;
    private String password;


    public Student(int id, String name, String password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }

}
public class Test2 {
    public static void main(String[] args){

        Student s1 = new Student(1, "小王", "123456");
        Student s2 = new Student(1, "小王", "123456");
        System.out.println(s1 == s2);//false

        System.out.println(s1.equals(s2));//false
    }
}

上面兩個對象s1和s2不相等,由於他們指向的是兩個不一樣的對象,因此引用不一樣,可是咱們的目的是要達到若是id,name,password都相同,那麼就是同一個對象,因此須要重寫equals()方法this

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Student student = (Student) o;

    if (id != student.id) return false;
    if (name != null ? !name.equals(student.name) : student.name != null) return false;
    return password != null ? password.equals(student.password) : student.password == null;
}

這個時候咱們再運行.net

public class Test2 {
    public static void main(String[] args){

        Student s1 = new Student(1, "小王", "123456");
        Student s2 = new Student(1, "小王", "123456");
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true
    }
}

對於string類型來講,它的的equals()方法是對object方法的equals()進行了重寫,從而比較的字符串序列是code

否相同以下:對象

String s1 = new String("abc");//s1存在於堆內存中
String s2 = new String("abc");//s2也存在於堆內存中
System.out.println(s1 == s2);//false s1和s2指向的對象的首地址不同,不是同一個對象
System.out.println(s1.equals(s2));//true  s1和s2指向的對象的內容相同

ps:blog

String s3 = "abc";
String s4 = "abc";
System.out.println(s3 == s4);//true 
System.out.println(s3.equals(s4));//true

接下來咱們討論一下重寫equals()方法的同時必需要重寫hashcode()方法嗎索引

​ 首先咱們重寫equals()的目的就是爲了讓內容相同的對象讓它們相同,而不是單單隻比較對象的引用(對象的首地址),也就是儘管這兩個對象的引用地址不一樣,可是咱們調用equals方法的時候仍然返回true

​ 那麼這個時候咱們爲何又要重寫hashcode方法呢,hashcode()返回的是對象的地址,是一個散列值,那麼若是咱們經過equals()方法獲得這兩個對象相同,儘管他們在堆中的內存地址不同,可是咱們但願他們的哈希值是同樣的,這樣若是存入map的話,就能定位到相同的索引

​ 同時Java標準中對hashcode有以下的規定:

  • 在java應用程序執行期間,若是在equals方法比較中所用的信息沒有被修改,那麼在同一個對象上屢次調用hashCode方法時必須一致地返回相同的整數。若是屢次執行同一個應用時,不要求該整數必須相同。
  • 若是兩個對象經過調用equals方法是相等的,那麼這兩個對象調用hashCode方法必須返回相同的整數。
  • 若是兩個對象經過調用equals方法是不相等的,不要求這兩個對象調用hashCode方法必須返回不一樣的整數。

若是咱們不重寫student的hashcode()方法,那麼就會默認調用object的hashcode()方法:

public class Test2 {
    public static void main(String[] args){

        Student s1 = new Student(1, "小王", "123456");
        Student s2 = new Student(1, "小王", "123456");
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.hashCode());//356573597
        System.out.println(s2.hashCode());//1735600054
    }
}

咱們能夠看到以上的運行結果違背了hashcode的規定:若是equals()返回true,那麼hashcode方法必須返回相同的整數

因此咱們須要對student對象的hashcode方法進行重寫

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + (password != null ? password.hashCode() : 0);
    return result;
}

經過重寫hashcode()讓其與對象的屬性關聯起來,那麼就可以達到equals()爲true,那麼hashcode的值也相等。

如今咱們已經知道了重寫equals()方法的同時須要重寫對象的hashcode()方法,讓其知足hashcode的標準條件。

可是好奇的同窗可能會想到:爲何hashcode須要這樣定義標準呢,這樣作到底有什麼好處呢,除了讓equals()方法和hashcode()方法的返回值具備一致性。

這時咱們就須要提到map類了,咱們知道hashmap的結構是一個數組加鏈表組成的,咱們經過key的

​ hashcode % hashmap的capacity 定位到具體數組的索引,而後將該(key,value)放入該索引對應的鏈表裏面,這裏之因此爲鏈表就是爲了解決hash衝突,即hashcode % capacity 相同的值有不少,須要用一個鏈表存儲起來,若是想要鏈表短一點,也就是hash衝突少一點,那麼就須要減少hashmap的負載因子loadFacotor,固然這裏也就扯遠了,咱們繼續回到正題,

Student s1 = new Student(1, "小王", "123456");
Student s2 = new Student(1, "小王", "123456");

​ 對於s1和s2兩個對象,若是咱們咱們已經將s1存入一個map對象,那麼咱們再存入s2時,咱們但願的是這是不能再插入map了,由於此時map中已經存在小王這個對象了,那麼如何才能作到呢

​ 首先咱們經過s1的hashcode % capacity 獲得了一個數組索引,而後將s1這個對象存入map,那麼咱們再插入s2的時候一樣也須要計算它的hashcode,而後定位到相同的數組索引,而後判斷該鏈表中是否存在小王這樣一個對象,若是存在就不put

​ 因此咱們須要獲得的s1和s2的hashcode相同,才能避免同一個對象被put進入map中屢次,因此咱們才須要在重寫equals()方法的同時重寫equals()方法,讓兩個相等的對象具備相同的hashcode

​ 可能細心的盆友會發現若是咱們只是須要簡單的根據判斷兩個對象的內容是否相同來判斷兩個對象是否相等,而不涉及到ma'p操做,那麼其實也是不用重寫ha'shcode方法了,可是萬一哪天忽然不當心放進了map了呢,因此通常咱們重寫equals()方法的同時都會重寫hashcode(),確保萬無一失~

參考

重寫equal()時爲何也得重寫hashCode()之深度解讀equal方法與hashCode方法淵源

重寫equals方法後重寫hashCode方法的必要性

相關文章
相關標籤/搜索