【java】【集合】set集合、唯一性保證、Linkset、案例

love_Aym發表於2018-04-27

一、set概述

1、通過API檢視即可:方法和collection中的方法一模一樣,沒什麼特別的方法,主要學習set的子類如何保證元素的唯一性。

2、 特點:

  • 無索引:不可以通過索引值去操作集合
  • 不可以重複:add()新增時,如果發現值重複了就會返回false,表示儲存不成功
  • 無序(存取不一致)

3、遍歷:不能使用索引值遍歷,但是可以用迭代器遍歷(迭代器或增強for迴圈)

	public static void demo1() {
		HashSet<String> hs = new HashSet<>();	//建立HashSet物件
		boolean b1 = hs.add("a");
		boolean b2 = hs.add("a");	//當向set集合中儲存重複元素的時候返回為false
		hs.add("b");
		hs.add("c");
		hs.add("d");
		System.out.println(hs);		//HashSet的繼承體系中有重寫toString方法
		System.out.println(b1);
		System.out.println(b2);
		
		for (String string : hs) {	//只要能用迭代器迭代的,就可以使用增強for迴圈遍歷
			System.out.println(string);
		}
	}

二、HashSet原理

1、原理

  • 我們使用Set集合都是需要去掉重複元素的,如果在儲存的時候逐個equals()比較,效率較低:可以先判斷hashcode值,如果相同再去呼叫equals比較。雜湊演算法提高了去重複的效率, 降低了使用equals()方法的次數
  •  當HashSet呼叫add()方法儲存物件的時候,先呼叫物件的hashCode()方法得到一個雜湊值, 然後在集合中查詢是否有雜湊值相同的物件:(只有hashcode值相同的時候才去呼叫equals方法)
  • 如果沒有雜湊值相同的物件就直接存入集合
  • 如果有雜湊值相同的物件,就和雜湊值相同的物件逐個進行equals()比較,比較結果為false就存入,true則不存

2、將自定義類的物件存入HashSet去重複

  • 類中必須自己重寫hashCode()和equals()方法:(為了保證set中元素的唯一性),如果不重寫equals方法,equals方法是按照物件的地址值比較,new物件的地址值都不同,因此可能會將相同物件當做不同物件進行儲存,無法保證元素的唯一性
  • hashCode():屬性相同的物件返回值必須相同, 屬性不同的返回值儘量不同(提高效率,降低使用equals方法的次數)
  • equals():屬性相同返回true, 屬性不同返回false,返回false的時候儲存

注意:若不是自定義物件,java會自動重寫hashcode和equals方法來保證set集合元素的唯一性

下面是Person物件傳入set集合時java自動重寫:

/*
	 * 為什麼是31?
	 * 1,31是一個質數,質數是能被1和自己本身整除的數
	 * 2,31這個數既不大也不小
	 * 3,31這個數好算,2的五次方-1,2向左移動5位
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)				//呼叫的物件和傳入的物件是同一個物件
			return true;				//直接返回true
		if (obj == null)				//傳入的物件為null
			return false;				//返回false
		if (getClass() != obj.getClass())		//判斷兩個物件對應的位元組碼檔案是否是同一個位元組碼
			return false;				//如果不是直接返回false
		Person other = (Person) obj;			//向下轉型
		if (age != other.age)			        //呼叫物件的年齡不等於傳入物件的年齡
			return false;				//返回false
		if (name == null) {				//呼叫物件的姓名為null
			if (other.name != null)			//傳入物件的姓名不為null
				return false;			//返回false
		} else if (!name.equals(other.name))	        //呼叫物件的姓名不等於傳入物件的姓名
			return false;				//返回false
		return true;					//返回true
	}

三、LinkedHashSet

  • 底層是連結串列實現的,是set集合中唯一一個能保證怎麼存就怎麼取的集合物件,即按照順序去存和取
  • 因為是hashset的子類所以也是保證元素唯一的,與hashset的原理一樣

四、案例練習

1、編寫一個程式,獲取10個1至20的隨機數,要求隨機數不能重複。並把最終的隨機數輸出到控制檯。

HashSet<Integer> hs = new HashSet<>();		//建立集合物件
Random r = new Random();					//建立隨機數物件
			
while(hs.size() < 10) {
    int num = r.nextInt(20) + 1;			//生成1到20的隨機數
    hs.add(num);
}
			
for (Integer integer : hs) {				//遍歷集合
    System.out.println(integer);			//列印每一個元素
}			

2、使用Scanner從鍵盤讀取一行輸入,去掉其中重複字元, 列印出不同的那些字元

Scanner sc = new Scanner(System.in);		//建立鍵盤錄入物件
System.out.println("請輸入一行字串:");
String line = sc.nextLine();			//將鍵盤錄入的字串儲存在line中
char[] arr = line.toCharArray();		//將字串轉換成字元陣列
HashSet<Character> hs = new HashSet<>();	//建立HashSet集合物件
			
for(char c : arr) {				//遍歷字元陣列
    hs.add(c);					//將字元陣列中的字元新增到集合中
}
			
for (Character ch : hs) {			 //遍歷集合
    System.out.println(ch);
}

3、將集合中的重複元素去掉

分析:

  • 建立List集合儲存若干個重複元素
  • 單獨定義方法去除重複

  • 分析:
    * 去除List集合中的重複元素
    * 1,建立一個LinkedHashSet集合
    * 2,將List集合中所有的元素新增到LinkedHashSet集合
    * 3,將list集合中的元素清除
    * 4,將LinkedHashSet集合中的元素新增回List集合中
  • 列印一下List集合
public static void main(String[] args) {
		//1,建立List集合儲存若干個重複元素
		ArrayList<String> list = new ArrayList<>();
		list.add("a");
		list.add("a");
		list.add("a");
		list.add("b");
		list.add("b");
		list.add("b");
		list.add("c");
		list.add("c");
		list.add("c");
		list.add("c");
		
		//2,單獨定義方法去除重複
		getSingle(list);
		
		//3,列印一下List集合
		System.out.println(list);
	}
	public static void getSingle(List<String> list) {
		//1,建立一個LinkedHashSet集合
		LinkedHashSet<String> lhs = new LinkedHashSet<>();
		//2,將List集合中所有的元素新增到LinkedHashSet集合
		lhs.addAll(list);
		//3,將list集合中的元素清除
		list.clear();
		//4,將LinkedHashSet集合中的元素新增回List集合中
		list.addAll(lhs);
	}



相關文章