首頁 > 軟體

Java中介面Set的特點及方法說明

2022-02-15 10:02:07

介面Set的特點及方法

1、特點:無序,不可重複;

2、實現類:新增的方法:

  • add(Object obj);
  • addAll(Collection c);

Set中沒有修改的方法,可以間接修改,先刪除再新增;

刪除的方法:

  • remove(Object obj);
  • removeAll(Collection c);
  • retainAll(Collection c)僅保留set中那些包含在指定的Collection中的元素;
  • clear()清除所有元素;

查詢的方法:

  • contains(Object obj)查詢set中是否包含指定元素,包含返回true;
  • containsAll(Collection c)查詢set中是否包含指定的多個元素,全部包含返回true;
  • isEmpty()判斷set是否為空,為空返回true;

3、set集合的遍歷:使用for迴圈;

使用iterator迭代器:it.hasNext()如果有下一個元素,返回true;

  • it.next()返回下一個元素;
  • it.remove()刪除迭代器返回的最後一個元素;

Set介面及其實現類

Set介面有兩個實現類

  • 雜湊集合:HashSet(Hash演演算法)
  • 樹集合:TreeSet(二元樹演演算法)

Set介面:Set儲存元素是無序不可以重複的

  • HashSet:元素是否重複是依據:元素自身equals比較進行判定的。
  • TreeSet:元素是否重複是依據:CompareTo方法返回是否為0。

因為Set介面也是Collection的子介面

所以也可以使用Collection實現的所有方法,其中常用的有:

  • 新增:add()
  • 刪除:remove()
  • 檢查元素是否存在:contains(Object o)
  • 迭代器:iterator()

1、TreeSet:樹狀集合、存放有序

語法:Set<E> set = new TreeSet<E>();

說明:TreeSet新增元素時,首先按照compareTo()進行比較,而TreeSet要想指定集合的存放順序,被排序的物件需實現Comparable介面,這個介面強行的對每個實現類物件進行整體的排序,這種排序稱為類的自然排序,這個介面有個抽象方法compareTo,該方法稱為自然排序的方法。

向TreeSet中新增的元素必須是同一個類的。(否則底層呼叫compareTo時會報型別轉換異常)

public class Person implements Comparable{
	int id;
	int age;
	String name;
	public Person(int id,int age,String name){
		super();
		this.id = id;
		this.age = age;
		this.name = name;
	}
	public String toString(){
		return "Person [id = " + id + ", age = " + age + ", name = " + name + "]";
	}
	@Override
	public int compareTo(Object o){//按照id排序
		Person p;
		if(o instanceof Pserson){
			p = (Person)o;
		}else{
			return -1;//-1代表傳入的引數比我本身要小
		}
		int diff = this.id - p.id;
		if(diff!=0){
			diff = diff / Math.abs(diff);//差值除以本身絕對值,可以得到+1或-1的值。
		}
		return diff;
	}

該compareTo方法是根據物件的id進行比較,也可以根據自己的需求自定義比較內容:

  • this.id 是當前物件的id
  • o.id 是指定物件的id(也就是傳入物件的id)

呼叫sort方法時可以自定義升序或降序:

  • 升序:this.id - o.id(this.id < o.id 結果為負、this.id > o.id 結果為正,this.id = o.id 結果為0)
  • 降序:o.id - this.id(this.id < o.id 結果為正、this.id < o.id 結果為負,this.id = o.id 結果為0)

上述程式碼中,我們使用的是this.id - o.id,所以我們是升序排序的(預設情況就是升序排序的)。

import java.util.Set;
import java.util.TreeSet;
public class Demo{
	public static void main(String[] args){
		Set set = new TreeSet();
		Person p1 = new Person(1,18,"小明");
		Person p2 = new Person(2,5,"小強");
		Person p3 = new Person(3,20,"小張");
		set.add(p1);
		set.add(p2);
		set.add(p3);
		set.add(p3);//重複的元素不會被新增到集合中
		System.out.println(set.size());
		
		Iterator it = set.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}

compareTo方法就是為了實現Comparable介面而存在的,而實現Comparable介面就是為了可以直接使用sort()方法對該物件進行自定義排序。

注意:TreeSet是不能存在null元素(HashSet是可以儲存null值的),向TreeSet中新增元素時,首先按照compareTo()進行比較,元素底層呼叫compareTo方法時會報空指標異常。

2、HashSet:雜湊集合、高效快速

語法:Set<E> set = new HashSet<E>();

說明:HashSet儲存的物件,應該重寫hashCode()和equals()兩個方法,在新增元素的時候會根據我們重寫hashCode()方法計算元素的hash值,根據雜湊值計算元素儲存的位置(雜湊地址),如果該雜湊地址沒有元素則會直接新增成功,如果該位置有其他元素會根據equals方法判斷是否為同一個物件,如果結果返回true則不會新增,如果為false則會以連結串列的形式追加到該雜湊地址處。(底層根據HashMap實現)

在不指定泛型的情況下可以為不同的型別的值;

public class Person{
	int id;
	String name;
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	//重寫hashCode方法只根據id進行計算hash值
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}
	//重寫equals方法
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (id != other.id)
			return false;
		return true;
	}
	//重寫toString方法,方便在我們輸出的時候檢視
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + "]";
	}
}
public class Demo{
	public static void main(String[] args){
		Set set = new HashSet();
		Person p1 = new Person(1,"小明");
		Person p2 = new Person(2,"小張");
		Person p3 = new Person(3,"小李");
		set.add(p1);
		set.add(p2);
		set.add(p3);
		//在我們新增成功以後修改其決定hash值的id
		p2.id = 5;
		//在刪除時會導致刪除不掉(如果修改的是name則不會出現刪除不掉的效果)
		//因為之前的元素儲存在id為2計算的雜湊地址的位置,現在是去id為5計算的雜湊地址出去刪除,所以刪除不掉
		//set.remove(p2);
		//會新增到id為5計算的雜湊地址,所以會新增成功(雖然屬性相同,但是之前的是儲存在根據id為2計算的雜湊地址位置)
		set.add(p2);
		//當我們繼續新增的時候,equals返回的是true,所以不會新增成功
		set.add(p2);
		
		//此時建立一個id為2的物件繼續新增
		Person p4 = new Person(2,"小張");
		set.add(p4);//會新增id為2計算的雜湊地址位置,雖然該位置有元素,但是之前的元素已經被修改了,所以會新增成功
		System.out.println("集合的長度為:"+set.size());
		Iterator it = set.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}

輸出結果:

集合的長度:5
Person [id=1, name=小明]        //根據id為1計算的雜湊地址
Person [id=5, name=小張]        //根據id為2計算的雜湊地址(原p2物件以id為2的雜湊地址進行儲存,但是後來id被修改為5了)
Person [id=2, name=小張]        //根據id為2計算的雜湊地址(p4物件)
Person [id=3, name=小李]        //根據id為3計算的雜湊地址
Person [id=5, name=小張]        //根據id為5計算的雜湊地址(修改以後的p2以id為5計算的雜湊地址儲存)

HashSet儲存元素的儲存過程:

首先說一下HashSet儲存物件的方式:首先根據我們重寫的HashCode方法計算出Hash值,根據Hash值來判斷存入Set中的元素是否重複和儲存在Set集合中的雜湊地址,如果該Hash地址為空,則會直接將該物件儲存到該雜湊地址,如果該雜湊地址有元素,會根據equals方法判斷是否為同一個物件,如果結果返回true,說明兩個物件是同一物件,則不會新增該物件,如果返回的是false,說明元素本身是不同的,則會以連結串列的形式同時儲存到該雜湊地址的位置。

總結:說一下上面的執行過程,Set集合是根據我們重寫的HashCode方法中的屬性,來計算Hash值,來判斷存入Set中的元素是否重複和儲存在Set集合中雜湊地址,當我們在儲存之後再進行修改決定計算Hash值的屬性時,會導致程式出現意想不到的結果,我們首先根據id為2計算出了一個儲存該物件的雜湊地址,當我們修改了id為5後,再進行刪除操作時,它會根據id為5計算一個Hash值,去該Hash值對應的雜湊地址去刪除元素,因為我們之前儲存的雜湊地址是根據id為2計算出來的,所以會導致本應刪除的元素刪除不掉,而當我們再進行add的時候,我們根據id為5的Hash值去儲存時發現,id為5的地址並沒有元素,所以儲存成功,雖然和之前id為2時計算Hash值儲存位置的元素屬性值一樣,但是還是會儲存成功的,然而,當我們再建立一個id為2的物件進行儲存時,雖然雜湊地址相同,但此時之前根據該雜湊地址的物件已經改變了(id修改為5了),所以會將新建立的id為2的物件以連結串列的形式同時儲存在該雜湊地址的位置,所以當我們操作HashSet集合時,不要去修改決定計算Hash值的元素屬性。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com