1. 程式人生 > >java Set 類,hashSet類, hashCode方法

java Set 類,hashSet類, hashCode方法

集合中,Set裡面儲存的元素不能重複,沒有索引,存取順序不一致。

Set的繼承關係圖如下

Set介面繼承了Collection介面,

HashSet存放無序,不重複的元素常用方法

boolean add(E e)  新增一個元素,返回一個布林值,如果新增的元素在Set中存在,則新增不了,返回false

add的實現是先呼叫物件的hashCode方法,如果返回的hashCode值相同,再呼叫equals方法,判斷新增的元素是否在Set中存在,存在則不新增,不存在則新增.如果返回的hashCode值不同,就直接將元素新增到Set中,所以新增的元素要重寫hashCode()和equals()方法

int size() 返回Set的元素個數

void clear() 清空Set中所有元素

boolean contains(Object o) 返回Set中是否包含了特定元素

boolean isEmpty()   檢查Set中是否沒有元素,沒有就返回true,有就返回false
Iterator<E> iterator() 生成Set的迭代器物件

boolean remove(Object o) 在Set中刪除特定元素,如果此元素在Set中返回true,如果Set中沒有此元素返回false

示例:

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

public class HashSetTest01 {
	public static void main(String[] args) {
		Set<String> set = new HashSet<>();
		boolean b1 = set.add("a");
		boolean b2 = set.add("a");
		System.out.println(b1);// true
		System.out.println(b2);// false
		set.add("c");
		set.add("f");
		set.add("b");
		for (String s : set) {
			System.out.print(s + " ");
		} //列印結果為a b c f 可以看到跟Set中的元素跟存放順序無關 

	}
}
out:
true
false
a b c f 

hashCode()方法

hashCode方法可以配合基於雜湊的集合,這樣的雜湊集合一般使用在hash容器中包括HashSet、HashMap以及HashTable.

HashCode方法的作用就是將物件均勻雜湊分類,然後獲取到編號值,

類似於下圖,將相同或者相似物件歸為一類(hash code相同),再用equals方法判斷是否相同

equals方法和hashCode方法 的關係

在Map和Set這種儲存不重複元素的容器中,equals方法本來是可以比較出兩個物件是否相同,但是如果物件的個數太多的話,會影響效能,所以hashCode()可以先來一個預先判斷,將物件hashCode方法返回的hash code儲存在hash表中,下個物件hashCode方法返回的hash code如果在hash表中能找到,進行equals比較,如果hash表不存在此hash code,  說明這個物件沒有跟以前的重複,不需要進行equals比較

為什麼有了hashCode()方法還要equals方法,是因為hashCode()方法並不是完全可靠,不同物件的hash code值可能相同

 重寫hashCode()方法的必要性      Object類中的hashCode()方法只是返回當前物件的地址,相同的一個類,new建立兩個物件,由於他們在記憶體裡的地址不同,則他們的hashCode()不同,這顯然達不到我們想要hsahCode()預判斷的效果,所以要重寫hashCode()

針對Set,Map這種型別的容器,重寫equals()方法時也要重寫hashCode()方法

重寫hashCode方法時要注意:

  • 相等的物件(equals比較為true)必須具有相等的雜湊碼(hash code)。
  • 不等的物件(equals比較為false),雜湊碼(hash code)值可以相等也可以不相等.
  • 任何時候對同一物件多次呼叫 hashCode 方法,都必須一直返回同樣的整數 

 示例:

package students;

public class Student {
	private int age;
	private String name;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Student [age=" + age + ", name=" + name + "]";
	}
        //eclipse自動生成的hashCode方法
	@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;
	}

	@Override
	public boolean equals(Object obj) {
		System.out.println("equals");
		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;
	}
}
//測試類
import java.util.HashSet;
import java.util.Set;

import students.Student;

public class HashSetTest02 {
	public static void main(String[] args) {
		Set<Student> set = new HashSet<>();
		set.add(new Student(12, "張三"));
		set.add(new Student(13, "李四"));
		set.add(new Student(14, "趙五"));
		set.add(new Student(12, "張三"));
		set.add(new Student(13, "李四"));
		System.out.println(set); // 如果物件類沒有重寫hashCode,Set不會去重,會把所有元素新增到Set中
									// 物件類重寫hashCode方法後,Set就會去重

	}
}
out:
equals
equals
[Student [age=14, name=趙五], Student [age=12, name=張三], Student [age=13, name=李四]]

當自定義的類只有int age和String name這兩個屬性時,eclipse自動生成的hashCode方法:

	@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;
	}

 為什麼eclipse自動重寫的hashCode方法中的prime為31?

     其實這個值改成別的也可以,只不過定義為31之後有一些好處:

  • 31是一個質數,質數是能被1和自己本身整除的數,並且這個數不大也不小
  • 31這個數好算,2的五次方-1,2向左移動5位

參考 :  http://www.monkey1024.com/javase/573