JAVA知識點回顧之HashCode、Equals和==

1. 運算符 ==

在Java中數據類型分爲兩大類:基本數據類型(byte,short,char,int,long,float,double,boolean)和引用數據類型(類、接口和數組)。

  • 基本數據類型
    在基本數據類型中,== 操作比較的是兩個變量的是否相等。
  • 引用數據類型
    在引用數據類型中,== 操作比較的是兩個對象在內存中的引用地址。引用類型在棧中存放的是對象引用(地址),對象是放在堆中。

2. Equals 方法

equals 是 Object類默認提供的方法。

  • 沒有覆蓋情況
    主要用於判斷對象的內存地址是不是同一個地址(是不是同一個對象)
// Object 類equals 源碼
public boolean equals(Object obj) {
    return (this == obj);
    }
  • 覆蓋情況
    要是覆蓋equals方法情況下,則根據具體的代碼來確定equals方法的作用。一般都是通過對象的內容是否相等來判斷對象是否相等
// String 類 equals 源碼
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
    }
判斷相等的步驟:
1. 比較兩個String對象是否爲同一對象,如果是就直接返回true
2. 如果不是同一對象,先確定傳入的對象是否是String類型,如果是,則比較兩對象的字符序列
3. 遍歷過程中只要有一個字符不相同,就返回false,否則返回true

補充 :覆蓋equals需遵守通俗約定

  • 自反性: 對於任何非null的引用值x, x.equals(x)必須返回true
  • 對稱性: 對於任何非null的引用值x和y, 當且僅當y.equals(x)返回true時,x.equals(y)必須返回true
  • 傳遞性: 對於任何非null的引用值x,y,z, 如果x.equals(y)爲true,並且y.equals(z)也返回true,那麼x.equals(z)也必須返回true
  • 一致性: 對於任何非null的引用值x和y, 只要equals的比較操作在對象中所用的信息沒有被修改,多次調用x.equals(y)就會一致地返回true,或者false
  • 對於任何非null的引用值x, x.equals(null)必須返回false

3.HashCode

hashCode方法返回值是Int型數據,這個值稱爲哈希碼(散列碼)。作用:確定該對象在散列表中的索引位置。

  // Object 類的源碼
  public native int hashCode();
應用

在Java裏集合可以存儲大量的數據,那麼Set集合中元素是無序且不可重複的,那麼Set集合如何來保證元素不重複呢?通過迭代來 equals() 是否相等。數據量小還可以接受,當我們的數據量大的時候效率可想而知。hashCode 提供瞭解決方案。

hashCode是一個本地方法,它的實現與本地機器有關。當我們向一個集合中添加某個元素,集合會首先調用 hashCode 方法,這樣就可以直接定位它所存儲的位置,若該處沒有其他元素,則直接保存。若該處已經有元素存在,就調用 equals 方法來匹配這兩個元素是否相同,相同則不存,不同則散列到其他位置。這樣處理,當我們存入大量元素時就可以大大減少調用 equals() 方法的次數,極大地提高了效率。

hashCode 方法和equals 方法關係

Java 中,當用到HashMap、HashSet、HashTable這類的集合框架時,比如,將自己新建的類作爲 HashMap 的 key。這種情況下,需要重寫hashCode和equals方法
例子

public class EqHashCode {

	public static void main(String[] args) {
		Student stu=new Student("小米","一班");
		Student stu1=new Student("小米","一班");

		HashMap<Student, String> hashMap = new HashMap<>();
		hashMap.put(stu,stu.className);
		hashMap.put(stu1,stu1.className);

		System.out.println(hashMap.size());
		System.out.println(stu==stu1);
		System.out.println(stu.equals(stu1));
	}

}

public class Student {
	public String name;
	public String className;

	public Student(String name, String className) {
		super();
		this.name = name;
		this.className = className;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj instanceof Student) {
			Student stu = (Student) obj;
			if (name.equals(stu.name) && className.equals(stu.className)) {
				return true;
			}
		}

		return false;
	}

	@Override
	public int hashCode() {
		int result = 17;// 非0 任選
		result = 31 * result + name.hashCode();
		result = 31 * result + className.hashCode();
		return result;
	}

}
運行結果:
第一次equals 方法沒有覆蓋情況下,hashMap size爲2;第二次覆蓋equals 方法下,hashMap size爲1
總結
  1. 如果兩個對象相等,則hashcode一定也是相同的
  2. 如果兩個對象相等,則兩個對象分別調用equals方法都返回true
  3. 兩個對象有相同的hashcode值,它們也不一定是相等的
  4. equals 方法被覆蓋過,則 hashCode 方法也必須被覆蓋
  5. hashCode() 的默認行爲是對堆上的對象產生獨特值。如果沒有重寫 hashCode(),則該 類的兩個對象無論如何都不會相等(即使這兩個對象指向相同的數據)

參考
你重寫過 hashcode 和 equals 麼,爲什麼重寫equals時必須重寫hashCode方法?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章