Set 介面是 Collection 介面的一個子介面。Set 介面的實現類不會包含重覆的元素,並且最多只能有一個 null 元素。當嘗試添加重覆元素時,添加操作將被忽略。Set 介面取出元素的順序和添加元素的順序不一致(但是每次取出的順序是固定的),即無法通過索引訪問 Set 中的元素。 ...
Set 介面基本介紹
Set
介面是Collection
介面的一個子介面,其主要特點如下:
-
不允許重覆元素:
Set
介面的實現類不會包含重覆的元素。更正式地說,不包含任何一對使得e1.equals(e2)
成立的元素e1
和e2
,並且最多只能有一個null
元素。當嘗試添加重覆元素時,添加操作將被忽略。 -
無序性:
Set
介面取出元素的順序和添加元素的順序不一致(但是每次取出的順序是固定的),即無法通過索引訪問Set
中的元素。
Set
介面的常用實現類有HashSet
、TreeSet
和LinkedHashSet
。可以使用迭代器和增強 for 迴圈遍歷元素,但是不能使用普通 for 迴圈(不能使用索引)。下麵的代碼以其實現類HashSet
演示Set
介面的特點。
public class TestSet() {
public static void main(String[] args) {
Set set = new HashSet();
set.add("Phoebe");
set.add("Monica");
set.add("Phoebe"); // 重覆
set.add("Ross");
set.add("Chandler");
set.add("Rachel");
set.add(null);
set.add(null); // 再次添加 null
// 10 次輸出結果均為:set=[Phoebe, null, Rachel, Ross, Chandler, Monica]
// 重覆的 Phoebe 和 null 都只輸出了一個,
// 取出順序和添加順序不一致但每次取出順序都是相同的。
for (int i = 0; i < 10; i++) {
System.out.println("set=" + set);
}
}
}
註意:如果Set
集合的元素是可變對象時,必須要小心。如果以影響equals()
方法比較結果的方式修改Set
中的元素的值,集合的行為是未指定的。這種情況的特例是Set
不能將自身作為元素。以下以一個簡單的 Person 類來測試修改HashSet
中元素的值使得兩個元素equals()
方法比較結果相同時的情況。
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class TestModifyValue() {
public static void main(String[] args) {
Set set = new HashSet();
// 創建 3 個 Person 實例,其中 rose1.equals(rose2) 成立
Person jack = new Person("Jack");
Person rose1 = new Person("Rose");
Person rose2 = new Person("Rose");
// 將其添加到 set 中
set.add(jack);
set.add(rose1);
set.add(rose2);
// 可以看到只添加成功一個姓名為 Rose 的 Person 實例,其應為 rose1。
System.out.println("set = " + set); // set = [Person{name='Rose'}, Person{name='Jack'}]
// 將 set 添加到自身中,未添加成功
set.addAll(set);
System.out.println("set = " + set); // set = [Person{name='Rose'}, Person{name='Jack'}]
// 將 rose1 的 name 屬性修改為 Jack
rose1.setName("Jack");
System.out.println(rose1.equals(jack)); // true
// 可以看到此時 set 集合中仍有兩個對象,其 equals() 方法比較結果相同。
System.out.println("set = " + set); // set = [Person{name='Jack'}, Person{name='Jack'}]
}
}
Set 介面常用方法
Set
介面和List
介面一樣,也是Collection
介面的子介面,因此常用方法和Collection
介面一樣。但需要註意由於Set
介面不包含重覆元素,所以addAll()
方法的參數也是Set
時,addAll
操作會有效地修改該集合,使其值為兩個集合的並集。
public class SetAddAll() {
public static void main(String[] args) {
Set set = new HashSet();
set.add("Phoebe");
set.add("Monica");
set.add("Ross");
System.out.println("set = " + set); // set = [Phoebe, Ross, Monica]
Set set1 = new HashSet();
set1.add("Phoebe");
set.add("Chandler");
set.addAll(set1);
System.out.println("set = " + set); // set = [Phoebe, Ross, Chandler, Monica]
}
}
Set 介面遍歷元素方式
Set
介面遍歷元素的方式和Collection
介面的一樣,可以使用迭代器和增強 for 迴圈來遍歷元素,但不能通過索引的方式來遍歷元素。
public class SetThroughElements() {
public static void main(String[] args) {
Set set = new HashSet();
set.add("Phoebe");
set.add("Monica");
set.add("John");
System.out.println("---使用迭代器---");
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj = " + obj);
}
System.out.println("---使用增強 for---");
for (Object o :set) {
System.out.println("o = " + o);
}
// 不能使用普通 for 迴圈,因為 Set 不支持索引
}
}