java.util.Set
接口和 java.util.List 接口一樣,同樣繼承自 Collection 接口,它與 Collection 接口中的方 法基本一緻,并沒有對 Collection 接口進行功能上的擴充,隻是比 Collection 接口更加嚴格了。與 List 接口不 同的是, Set 接口中元素無序,并且都會以某種規則保證存入的元素不出現重複。
Set 集合有多個子類,這裡我們介紹其中的
java.util.HashSet
、
java.util.LinkedHashSet
這兩個集合。
tips:Set集合取出元素的方式可以采用:疊代器、增強for。
3.1 HashSet集合介紹
java.util.HashSet
是 Set 接口的一個實作類,它所存儲的元素是不可重複的,并且元素都是無序的(即存取順序 不一緻)。
java.util.HashSet
底層的實作其實是一個
java.util.HashMap
支援,由于我們暫時還未學習,先做了解。
HashSet 是根據對象的哈希值來确定元素在集合中的存儲位置,是以具有良好的存取和查找性能。保證元素唯一性 的方式依賴于: hashCode 與 equals 方法。
我們先來使用一下Set集合存儲,看下現象,再進行原理的講解:
public class HashSetDemo {
public static void main(String[] args) {
//建立 Set集合
HashSet<String> set = new HashSet<String>();
//添加元素
set.add(new String("cba"));
set.add("abc");
set.add("bac");
set.add("cba");
// 周遊
for (String name : set) {
System.out.println(name);
}
}
}
輸出結果如下,說明集合中不能存儲重複元素:
cba
abc
bac
tips:根據結果我們發現字元串"cba"隻存儲了一個,也就是說重複的元素set集合不存儲。
2.2 HashSet集合存儲資料的結構(哈希表)
什麼是哈希表呢?
在JDK1.8之前,哈希表底層采用數組+連結清單實作,即使用連結清單處理沖突,同一hash值的連結清單都存儲在一個連結清單裡。 但是當位于一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。而JDK1.8中,哈 希表存儲采用數組+連結清單+紅黑樹實作,當連結清單長度超過門檻值(8)時,将連結清單轉換為紅黑樹,這樣大大減少了查找 時間。
看到這張圖就有人要問了,這個是怎麼存儲的呢?
為了友善大家的了解我們結合一個存儲流程圖來說明一下:
總而言之,JDK1.8引入紅黑樹大程度優化了HashMap的性能,那麼對于我們來講保證HashSet集合元素的唯一, 其實就是根據對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那麼保證其唯一, 就必須複寫hashCode和equals方法建立屬于目前對象的比較方式。
2.3 HashSet存儲自定義類型元素
給HashSet中存放自定義類型元素時,需要重寫對象中的hashCode和equals方法,建立自己的比較方式,才能保 證HashSet集合中的對象唯一
建立自定義Student類
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class HashSetDemo2 {
public static void main(String[] args) {
//建立集合對象 該集合中存儲 Student類型對象
HashSet<Student> stuSet = new HashSet<Student>();
//存儲
Student stu = new Student("于謙", 43);
stuSet.add(stu);
stuSet.add(new Student("郭德綱", 44));
stuSet.add(new Student("于謙", 43));
stuSet.add(new Student("郭麒麟", 23));
stuSet.add(stu);
for (Student stu2 : stuSet) {
System.out.println(stu2);
}
}
}
執行結果
執行結果:
Student [name=郭德綱, age=44]
Student [name=于謙, age=43]
Student [name=郭麒麟, age=23]
2.3 LinkedHashSet
我們知道HashSet保證元素唯一,可是元素存放進去是沒有順序的,那麼我們要保證有序,怎麼辦呢? 在HashSet下面有一個子類
java.util.LinkedHashSet
,它是連結清單和哈希表組合的一個資料存儲結構。 示範代碼如下:
2.4 可變參數
在JDK1.5之後,如果我們定義一個方法需要接受多個參數,并且多個參數類型一緻,我們可以對其簡化成如下格式:
修飾符 傳回值類型 方法名(參數類型... 形參名){ }
其實這個書寫完全等價與
修飾符 傳回值類型 方法名(參數類型[] 形參名){ }
隻是後面這種定義,在調用時必須傳遞數組,而前者可以直接傳遞資料即可。
JDK1.5以後。出現了簡化操作。… 用在參數上,稱之為可變參數。
同樣是代表數組,但是在調用這個帶有可變參數的方法時,不用建立數組(這就是簡單之處),直接将數組中的元素 作為實際參數進行傳遞,其實編譯成的class檔案,将這些元素先封裝到一個數組中,在進行傳遞。這些動作都在編 譯.class檔案時,自動完成了。