Java Set接口contains(Object o)方法與對象hashCode()方法的關係梳理

概述

接下來我們要討論如下問題:
1、Set接口的contains方法,判斷是否包含的依據是什麼?
2、對象hashCodeequals方法之間的關係

1、Set接口的contains方法,判斷是否包含的依據是什麼?

我查看了一下接口文檔,裏面是這樣描述的:
該方法重寫了Collection接口的contains方法

Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o == null ? e==null : o.equals(e)).

也就是說,當且僅當
1:參數o,如果o爲空,set中也有空時
2:參數o.equals(e),e爲set中的一個元素
上述兩種情況,會返回true。

2、對象hashCodeequals方法之間的關係

同樣,閱讀接口文檔,equals方法說明如下:

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes

就是說,如果一個對象重寫了equals方法,通常也需要重寫hashCode方法。根據契約約定,如果兩個對象相等,則它們的hash值必須相等。
換句話說,如果兩個對象的hash值不同,則調用它們的.equals去比較,肯定返回false

閱讀hashCode的文檔說明:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

如果兩個對象相等,則必須返回相等的hash值。這和equals說明一致。

It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

簡單的說,如果兩個對象不相等,它們的hash值可能相等。
所以,不能認爲hash值一樣,就說兩個對象相等。

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

通常,不同對象還是需要返回不同的hash值。通常是通過將對象的內部地址轉換爲integer實現的。

代碼驗證

我自定義一個Dog對象,先不重寫equalshashCode,當Set中添加了兩個白色的狗對象時,我們用contains方法去校驗Set中是否包含白色的狗對象,會得到如下結果:

import java.util.HashSet;
import java.util.Set;

/**
 * created at 2018-10-08 17:24
 * @author lerry
 */

class Dog {
	String color;

	public Dog(String s) {
		color = s;
	}
}

public class SetAndHashCode {

	public static void main(String[] args) {
		Set<Dog> dogSet = new HashSet<>();
		dogSet.add(new Dog("white"));
		dogSet.add(new Dog("white"));

		System.out.printf("we have %d white dogs", dogSet.size());
		System.out.println();

		if (dogSet.contains(new Dog("white"))) {
			System.out.println("Set has white dog!");
		}
		else {
			System.out.println("Set don't have white dog!");
		}

	}
}
/*
console results:
we have 2 white dogs
Set don't have white dog!
 */

這說明:
默認new一個新對象,會產生新的hash值。

可以驗證一下:

public class SetAndHashCode {
	public static void main(String[] args) {
		System.out.println(new Dog("white").hashCode());
		System.out.println(new Dog("white").hashCode());
	}
}
/*
console results:
2000502626
704603837
 */

接下來,我們重新Dog類的equals方法,讓類認爲只要顏色一樣,就算相等:

class Dog {
	String color;

	public Dog(String s) {
		color = s;
	}

	public String getColor() {
		return color;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Dog && this.color.equals(((Dog) obj).getColor())) {
			return true;
		}
		else {
			return false;
		}
	}
}

public class SetAndHashCode {

	public static void main(String[] args) {
		Set<Dog> dogSet = new HashSet<>();
		dogSet.add(new Dog("white"));
		dogSet.add(new Dog("white"));

		System.out.printf("we have %d white dogs", dogSet.size());
		System.out.println();

		if (dogSet.contains(new Dog("white"))) {
			System.out.println("Set has white dog!");
		}
		else {
			System.out.println("Set don't have white dog!");
		}

	}
}
/*
console results:
we have 2 white dogs
Set don't have white dog!
 */

但是結果並沒有什麼改變。對了,根據如果兩個對象相等,則它們的hash值必須相等原則,我們還應該去重寫hashCode方法:

@Override
	public int hashCode() {
		return this.color.hashCode();
	}

這時,控制檯返回的結果終於變成了:

we have 1 white dogs
Set has white dog!

Set對重複元素,進行了去重。所以,添加了兩次

		dogSet.add(new Dog("white"));
		dogSet.add(new Dog("white"));

後,dogSet.size()依舊爲1

參考

Java中hashCode與equals方法的約定及重寫原則
jdk api

代碼環境描述

jdk 1.7
macOS 10.13.4

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