HashSet 實現類

Ernest圖南發表於2022-01-20

HashSet 實現類

通過 HashCode 判斷元素是否存在,若存在則不新增,否則新增以此實現唯一性

常用方法

Modifier and Type Method and Description
boolean add(E e) 將指定的元素新增到此集合(如果尚未存在)。
void clear() 從此集合中刪除所有元素。
Object clone() 返回此 HashSet例項的淺層副本:元素本身不被克隆。
boolean contains(Object o) 如果此集合包含指定的元素,則返回 true
boolean isEmpty() 如果此集合不包含元素,則返回 true
Iterator<E> iterator() 返回此集合中元素的迭代器。
boolean remove(Object o) 如果存在,則從該集合中刪除指定的元素。
int size() 返回此集合中的元素數(其基數)。
Spliterator<E> spliterator() 在此集合中的元素上建立late-binding故障快速 Spliterator

演示

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetDemo {
	public static void main(String[] args) {
		HashSet<String> test = new HashSet<>();
		test.add("華為");
		test.add("蘋果");
		test.add("小米");
		System.out.println(test.size());
		System.out.println(test);
		//新增重複元素不會進行新增
		test.add("華為");
		System.out.println(test);
		//刪除元素,由於 Set 集合沒有下標,只能指定值進行刪除
		test.remove("華為");
		System.out.println(test);
		//再次新增進來是無序的
		test.add("華為");
		//集合的遍歷
		System.out.println("-----for------");
		for (String string : test) {
			System.out.println(string);
		}
		System.out.println("-----Iterator-----");
		Iterator<String> it = test.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

重寫 hashcode equals 方法

注:可以通過系統根據自動重寫這兩個方法

儲存方式

  1. 根據元素的 hashcode 方法計算儲存位置,若該位置不存在元素則直接儲存,否則進入下一步
  2. 再執行 equals 方法,若返回值為 true 則認為元素重複;否則形成連結串列

image-20220120155908304

未重寫方法時

import java.util.HashSet;
public class HashDemo {
	private String name;
	private int age;
	public HashDemo(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "HashDemo [name=" + name + ", age=" + age + "]";
	}
	public static void main(String[] args) {
		HashSet<HashDemo> hash = new HashSet<>();
		HashDemo h1 = new HashDemo("張三", 20);
		HashDemo h2 = new HashDemo("李四", 21);
		HashDemo h3 = new HashDemo("王五", 22);
		hash.add(h1);
		hash.add(h2);
		hash.add(h3);
		System.out.println(hash.size());
		System.out.println(hash);
		//新增同一個物件將會被equals判別為true,將不會將此物件進行再次新增
		hash.add(h1);
		System.out.println(hash.size());
		System.out.println(hash);
		//但是對於相同的值的不同物件,卻能夠新增
		hash.add(new HashDemo("張三", 20));
		System.out.println(hash.size());
         System.out.println(hash);
	}
}

未對方法進行重寫之前,對於用於相同數值的不同物件依然能夠進行新增,這樣不符合不重複的法則,因此對方法進行重寫,重寫後程式碼如下

只對 hanshcode 進行重寫後的程式碼如下

import java.util.HashSet;
public class HashDemo {
	private String name;
	private int age;
	public HashDemo(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "HashDemo [name=" + name + ", age=" + age + "]";
	}
	
	//重寫hashcode方法使hashcode只與姓名和年齡有關
	@Override
	public int hashCode() {
		int n1 = this.name.hashCode();
		int n2 = this.age;
		return n1 + n2;
	}
	public static void main(String[] args) {
		HashSet<HashDemo> hash = new HashSet<>();
		HashDemo h1 = new HashDemo("張三", 20);
		HashDemo h2 = new HashDemo("李四", 21);
		HashDemo h3 = new HashDemo("王五", 22);
		hash.add(h1);
		hash.add(h2);
		hash.add(h3);
		System.out.println(hash.size());
		System.out.println(hash);
		//新增同一個物件將會被equals判別為true,將不會將此物件進行再次新增
		hash.add(h1);
		System.out.println(hash.size());
		System.out.println(hash);
		//但是對於相同的值的不同物件,卻能夠新增
		hash.add(new HashDemo("張三", 20));
		System.out.println(hash.size());
		System.out.println(hash);
	}
}
3
[HashDemo [name=王五, age=22], HashDemo [name=張三, age=20], HashDemo [name=李四, age=21]]
3
[HashDemo [name=王五, age=22], HashDemo [name=張三, age=20], HashDemo [name=李四, age=21]]
4
[HashDemo [name=王五, age=22], HashDemo [name=張三, age=20], HashDemo [name=張三, age=20], HashDemo [name=李四, age=21]]

依然能夠新增值相同的元素,但是與未重寫 hashcode 時的區別在於,新新增的元素沒有放在陣列中,由於其與 p1 擁有相同的 hashcode 因此新的元素和 p1 佔用相同的位置,只是形成連結串列儲存

如圖

image-20220120202719283

為不新增值相同的元素,因此再以上基礎上還需對 equals 進行重寫

import java.util.HashSet;
public class HashDemo {
	private String name;
	private int age;
	public HashDemo(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "HashDemo [name=" + name + ", age=" + age + "]";
	}
	
	//重寫hashcode方法使hashcode只與姓名和年齡有關
	@Override
	public int hashCode() {
		int n1 = this.name.hashCode();
		int n2 = this.age;
		return n1 + n2;
	}
	//重寫equals,當值相等時返回true
	@Override
	public boolean equals(Object obj) {
		if(obj == null) {
			return false;
		}
		if(this == obj) {
			return true;
		}
		if(obj instanceof HashDemo) {
			HashDemo h = (HashDemo)obj;
			if(this.name.equals(h.name) && this.age == h.age) {
				return true;
			} else {
				return false;
			}
		}
		return false;
	}
	
	public static void main(String[] args) {
		HashSet<HashDemo> hash = new HashSet<>();
		HashDemo h1 = new HashDemo("張三", 20);
		HashDemo h2 = new HashDemo("李四", 21);
		HashDemo h3 = new HashDemo("王五", 22);
		hash.add(h1);
		hash.add(h2);
		hash.add(h3);
		System.out.println(hash.size());
		System.out.println(hash);
		//新增同一個物件將會被equals判別為true,將不會將此物件進行再次新增
		hash.add(h1);
		System.out.println(hash.size());
		System.out.println(hash);
		//但是對於相同的值的不同物件,卻能夠新增
		hash.add(new HashDemo("張三", 20));
		System.out.println(hash.size());
		System.out.println(hash);
        //hash.remove(new HashDemo("張三", 20));	重寫equals後可使用這種方式刪除	
	}
}
3
[HashDemo [name=王五, age=22], HashDemo [name=張三, age=20], HashDemo [name=李四, age=21]]
3
[HashDemo [name=王五, age=22], HashDemo [name=張三, age=20], HashDemo [name=李四, age=21]]
3
[HashDemo [name=王五, age=22], HashDemo [name=張三, age=20], HashDemo [name=李四, age=21]]

可見,此時將不會新增相同的元素(對於人而言相同的)。

相關文章