1. 程式人生 > >hashcode和equals重寫規則

hashcode和equals重寫規則

HashSet

  HashSet底層是HashMap實現的。

因此HashSet無序不可重複,也就意味著存放到HashSet中的物件元素是經過排序比較的。

如何比較呢?

1.HashMap底層是根據hashcode和equals來存放物件的。

2.我們知道Object父類中的hashcode方法預設返回的是物件的地址值,因此如果不重寫hashcode,那麼預設比較的是存放到集合中的物件的地址值,那麼通過new出的物件,即使元素相同,也會被當做不同的元素而被HashSet去重,達不到我們想要的目的。

因此,要想根據我們的想法來實現對物件的去重,就需要我們重寫放入到HashSet中的自定義物件元素,只有HashSet有此需要。

如何重寫Hashcode和equals?

如何去合理的計算出一個不容易重複的hashcode?equals的比較是根據哪個屬性來比較?int和String一般是怎麼比較的?其他的基本型別或是引用型別呢?是不是感覺有點難度?

幸運的,一般HashCode 和equals的重寫,系統已經提供好了一種簡單通用的寫法,我們直接重寫即可。


我們新建一個MusicBox類,原始碼如下:
public class MusicBox {
	
	// 歌手
	private String person;
	
	// 歌名
	private String name;
	
	// 大小
	private double lenght;
	
	public MusicBox() {
		super();
	}
	public MusicBox(String person, String name, double lenght) {
		super();
		this.person = person;
		this.name = name;
		this.lenght = lenght;
	}
	public String getPerson() {
		return person;
	}
	public void setPerson(String person) {
		this.person = person;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getLenght() {
		return lenght;
	}
	public void setLenght(double lenght) {
		this.lenght = lenght;
	}
	
	@Override
	public String toString() {
		return "MusicBox [person=" + person + ", name=" + name + ", lenght=" + lenght + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		temp = Double.doubleToLongBits(lenght);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((person == null) ? 0 : person.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MusicBox other = (MusicBox) obj;
		if (Double.doubleToLongBits(lenght) != Double.doubleToLongBits(other.lenght))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (person == null) {
			if (other.person != null)
				return false;
		} else if (!person.equals(other.person))
			return false;
		return true;
	}
}

可以看到系統為我們提供好的hashcode和equals方法,不用我們去重複的編寫程式碼。

但是系統提供的也有缺點,那就是不能完全恰好滿足我們實際的需要,因為太通用了。

比如我們想根據歌曲名稱去重,而不是所有的屬性,怎麼辦呢?解決辦法有兩種:

1.   我們自己修改生成的程式碼來滿足我們的需求。

我們可以把上面的hashcode()和equals方法重寫成:

@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MusicBox other = (MusicBox) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

這樣,當hashcode相同時,如果物件name比較 equals相同,那麼就會去重,也就達到了我們的目的。

2.   自動生成時選擇我們的需求。

我們可以不用為所有編寫的屬性重寫hashcode和equals,而是隻重寫我們需要的。


也可以達到相同的目的。

具體除錯內容不再貼上。