Java基礎(十七)——Set集合、可變引數和Collections工具類
Set介面
java.util.set介面和java.util.List介面是一樣的,都是繼承自Collection介面,它與collection介面中的方法基本一樣,沒有對Collection介面進行功能上的擴充套件,只是比Collection介面更加嚴格。與List介面不同的是,Set介面中的元素是無序的,並且都會以某種規則保證存入的元素不重複。
Set集合取出元素的方式可以採用:迭代器、增強for迴圈。
HashSet集合介紹
java.util.HashSet是Set介面的一個實現類,它儲存的元素是不可重複的,並且元素都是無序的(存取順序不一致)。java.util.HashSet
HashSet是根據物件的雜湊值來確定元素在集合當中的儲存位置,因此它具有良好的存取和查詢效能。保證元素唯一性的方式依賴於hashCode和equals方法。
HashSet集合儲存資料的結構(雜湊表)
什麼是雜湊表呢?
在JDK1.8之前,雜湊表的底層採用的是陣列+連結串列實現,即使用連結串列處理雜湊衝突,同一雜湊值的連結串列都儲存在一個連結串列裡,但是當位於一個鏈中的元素較多時,即hash值相等的元素較多時,通過key值依次查詢的效率很低下。在JDK1.8中,雜湊表儲存結構採用陣列+連結串列/紅黑樹實現的,當連結串列的長度超過閾值(8)時,將連結串列轉換成紅黑樹結構,這樣的好處是大大減少了查詢的時間。
如圖展示:
總而言之,JDK1.8之後引入紅黑樹結構大大優化了HashMap的效能,那麼對於我們來講保證HashSet元素唯一不重複,其實是根據物件的hashCode和equals方法來決定的。如果我們往集合當中儲存的是自定義的物件,需要保證物件的唯一性,就必須重寫hashCode和equals方法,來自定義當前的物件的比較方式。
HashSet保證元素唯一的原理,如圖所示
HashSet儲存自定義型別的元素
一般需要重寫物件當中的hashCode和equals方法,建立自己的比較方式。才能保證HashSet集合中元素的唯一性。
程式碼示例:
1 @Override2 public boolean equals(Object o) { 3 if (o == null) { 4 return false; 5 } 6 if (this == o) { 7 return true; 8 } 9 // 向下轉型 型別判斷 10 if (o instanceof Student) { 11 Student student = (Student)o; 12 // 同名同年齡的人為同一個人 true 13 return student.getName().equals(name) && student.getAge() == age; 14 } 15 return false; 16 } 17 18 @Override 19 public int hashCode(){ 20 // 使用Objects類中的hash方法 21 return Objects.hash(name,age); 22 }
LinkedHashSet集合
我們知道HashSet保證元素的唯一,可是存進去的元素是沒有順序的,那麼如何保證存進去的元素是有序的?
在java.util.HashSet類的下面還有一個子類java.util.LinkedHashSet,它是連結串列和雜湊表的組合的一個數據儲存結構。程式碼示例:
1 // 構建一個LinkedHashSet集合物件 2 LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>(); 3 linkedHashSet.add("www"); 4 linkedHashSet.add("baidu"); 5 linkedHashSet.add("com"); 6 linkedHashSet.add("abc"); 7 linkedHashSet.add("abc"); 8 linkedHashSet.add("java"); 9 linkedHashSet.add("python"); 10 // [www, baidu, com, abc, java, python] 11 System.out.println(linkedHashSet);// [www, baidu, com, abc] 有序的,不重複的
可變引數
在JDK1.5之後,如果我們定義一個方法需要接受多個引數,並且多個引數的資料型別一致,那麼我們可以簡化成如下格式:
1 修飾符 返回值型別 方法名(引數型別... 形參名){ 2 //... 3 }
其實上面的格式完全等價於:
1 修飾符 返回值型別 方法名(引數型別[] 引數名){ 2 //.... 3 }
只是後面的寫法,在方法呼叫,必須傳遞一個數組型別,而前者可以直接傳遞引數資料。
JDK1.5之後,出現的這種簡化操作。"..."用在引數上,我們稱之為可變引數。
同樣是代表陣列,但是在方法呼叫這個帶有可變引數時,不用建立陣列,而是直接將陣列當中的元素作為實際引數進行傳遞,其實編譯生成的.class檔案,本質是將這些元素封裝到了一個數組當中,再進行資料傳遞,這些動作都在編譯生成.class檔案的時候,自動完成了。
程式碼示例:
1 public static void add(int... arr) { 2 //System.out.println(arr);// [I@1b6d3586 底層就是一個數組 3 //System.out.println(arr.length);//0 4 int sum = 0; 5 for (int i = 0; i < arr.length; i++) { 6 sum += arr[i]; 7 } 8 System.out.println(sum); // 30 9 }
Collections集合工具類
常用功能
public static <T> boolean addAll(Collection<? super T> c,T... elements)
:往集合中一次性新增多個元素。
public static <T> void shuffle(List<?> list)
:打亂集合中的元素順序。
public static <T> void sort(List<T> list)
:將集合中的元素按照預設規則排序。
public static <T> void sort(List<T> list,Comparator<? super T> c)
程式碼演示:
1 ArrayList<String> strs = new ArrayList<>(); 2 //往集合當中儲存元素 3 /*strs.add("abc"); 4 strs.add("小孫"); 5 strs.add("小劉"); 6 strs.add("小趙");*/ 7 8 //使用Collections集合工具類中的addAll 9 Collections.addAll(strs, "張三","老王","小金豆","孬蛋","老白乾"); 10 System.out.println(strs); 11 System.out.println("========================="); 12 Collections.shuffle(strs); 13 System.out.println(strs);
1 ArrayList<Integer> list01 = new ArrayList<>(); 2 Collections.addAll(list01, 124,234,566,324,765,342); 3 System.out.println(list01); 4 System.out.println("============================"); 5 Collections.sort(list01); 6 System.out.println(list01); 7 System.out.println("============================"); 8 ArrayList<String> list02 = new ArrayList<>(); 9 Collections.addAll(list02,"asd","sd","sc","sv","ac","b","vc","v","cs"); 10 Collections.shuffle(list02); 11 Collections.sort(list02); 12 System.out.println(list02);