天天看點

java集合03-set,hashset,linkedhashset,treesetSet接口

Set接口

無序,不可重複

具體實作類:HashSet LinkedHashSet TreeSet

set接口的架構結構

HashSet:作為set接口的主要實作類; 線程不安全,可以存儲null值

LinkedHashSet:作為HashSet的子類:周遊其内部資料時,可以按照添加的順序周遊

TreeSet:可以按照添加對象的指定屬性,進行排序

  • set接口中沒有額外定義新的方法,使用的都是collection中聲明過的方法。
  • 要求:向set中添加的資料,其所在類一定要重寫hashCode()和equals(),重寫的兩個方法盡可能保持一緻性,即“相等的對象有相等的散列碼”

以HashSet為例說明:

  1. 無序性 不等于 随機性;存儲的資料在底層數組中并非按照數組索引的順序添加,而是根據資料的哈希值進行添加
  2. 不可重複性:保證添加的元素按照equals()判斷時,不能傳回true。即相同的元素隻能添加一個。
package com.collection.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Demo00 {
    public static void main(String[] args) {
        test();
    }

    private static void test() {
        Set set = new HashSet();
        set.add(123);
        set.add(3);
        set.add(456);
        set.add(45);
        set.add("cc");
        set.add("aa");

        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
          // 列印的順訊并不是添加的順序
        }
    }
}
           

添加元素的過程

以HashSet為例

我們向HashSet中添加元素a,首先調用元素a所在類的hashCode()方法,計算元素a的哈希值,此哈希值接着通過某種算法計算出在HashSet底層數組中的存放位置(即為:索引位置),判斷此位置上是否已經有元素:

​ 如果此位置沒有其他元素,則元素a添加成功–情況1

​ 如果此位置有其他元素b(或以連結清單形式存在的多個元素),則比較元素a與元素b的hash值:

​ 如果hash值不相同,則元素a添加成功–情況2

​ 如果hash值相同,進而需要調用元素a所在類的equals()方法:

​ equals() 傳回true,元素a添加失敗

​ equals() 傳回false,元素a添加成功–情況3

對于添加成功的情況2和情況3而言:元素a與已經存在指定索引位置上資料以連結清單的方式存儲。

Jdk7:元素a放到數組中,指向原來的元素

Jdk8: 原來的元素在數組中,指向元素a

底層是數組結構+連結清單結構,初始容量為16。當如果使用率超過0.75,就會擴大容量為原來的2倍

LinkedHashSet的使用

LinkedHashSet作為HashSet的子類,在添加資料的同時,每個資料還維護了兩個引用,記錄此資料前一個資料和後一個資料

優點:對于頻繁的周遊操作,LinkedHashSet效率高于HashSet

// linkedhashset
    public static void test2(){
        Set set2 = new LinkedHashSet();
        set2.add(123);
        set2.add(3);
        set2.add(456);
        set2.add(45);
        set2.add("cc");
        set2.add("aa");

        Iterator iterator = set2.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
          // 列印順序是添加的順序
        }
    }
           

TreeSet的使用

  1. 向TreeSet中添加的資料,要求是相同類的對象
  2. 兩種排序方式:自然排序(實作comparable接口) 和 定制排序(comparator接口)
  3. 自然排序中,比較兩個對象是否相同的标準為:compareTo()傳回0,不再是equals(). 是以不能放相同的資料
  4. 定制排序中,自然排序中,比較兩個對象是否相同的标準為:compare()傳回0,不再是equals(). 是以不能放相同的資料
public static void test3() {
        TreeSet set3 = new TreeSet();
        //integer
//        set3.add(123);
//        set3.add(3);
//        set3.add(456);
//        set3.add(45);
//        set3.add(-3);
        //string
          set3.add("cc");
          set3.add("aa"); //不能添加不同類的對象
          set3.add("dd");
          set3.add("ee");
        Iterator iterator = set3.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
            // print按照從小到大的順序
        }
    }
           
private static void test4() {
  			// 按照age排序
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof User && o2 instanceof User){
                  User u1 = (User)o1;
                  User u2 = (User)o2;
                  return Integer.compare(u1.getAge(),u2.getAge());
                }else{
                  throw new RuntimeException("輸入的資料類型不比對")
                }
            }
        };
        TreeSet set4 = new TreeSet(com); // 有參,按照參數的方式排序
  // 不寫參數 則按照自然排序;寫了參數,定制排序
        set4.add(new User("tom",12));
  			set4.add(new User("joe",24));
  			set4.add(new User("amy",45));
    }
           

繼續閱讀