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
方法
注:可以通過系統根據自動重寫這兩個方法
儲存方式
- 根據元素的
hashcode
方法計算儲存位置,若該位置不存在元素則直接儲存,否則進入下一步 - 再執行
equals
方法,若返回值為true
則認為元素重複;否則形成連結串列
未重寫方法時
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
佔用相同的位置,只是形成連結串列儲存
如圖
為不新增值相同的元素,因此再以上基礎上還需對 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]]
可見,此時將不會新增相同的元素(對於人而言相同的)。