成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java的Set集合,你真的會用嗎?HashSet/TreeSet/LinkedHashSet

開發 前端
HashSet、LinkedHashSet、TreeSet,這三個常用的Set集合的共同點是都實現了Set接口,所以使用方式都是一樣的,使用add()?方法添加元素,使用remove()?刪除元素,使用contains()?方法判斷元素是否存在,使用iterator()方法迭代遍歷元素,這三個類都可以去除重復元素。

引言

當我們需要對元素去重的時候,會使用Set集合,可選的Set集合有三個,分別是HashSet、LinkedHashSet、TreeSet,這三個常用的Set集合有什么區別呢?底層實現原理是什么樣?這篇文章一起來深度剖析。

共同點這三個類都實現了Set接口,所以使用方式都是一樣的,使用add()方法添加元素,使用remove()刪除元素,使用contains()方法判斷元素是否存在,使用iterator()方法迭代遍歷元素,這三個類都可以去除重復元素。

特性

  1. HashSet是最基礎的Set集合,可以去除重復元素,元素存儲是無序的。
  2. LinkedHashSet在HashSet功能基礎上,增加了按照元素插入順序或者訪問順序的迭代方式。
  3. TreeSet在HashSet功能基礎上,可以保證按照元素大小順序排列。

底層實現

  1. HashSet是基于HashMap實現的,使用組合的方式,并非繼承。
  2. LinkedHashSet繼承自HashSet,而內部則是采用組合LinkedHashMap的方式實現的。[流汗] 就是這么亂,一會兒看一下源碼就明白了。
  3. TreeSet是基于TreeMap實現的,采用組合的方式,跟上面兩個Set集合沒關系。

圖片圖片

下面詳細看一下這三個Set集合源碼的底層實現:

HashSet源碼實現

類屬性

public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable {

    /**
     * 使用HashMap存儲數據
     */
    private transient HashMap<E, Object> map;

    /**
     * value的默認值
     */
    private static final Object PRESENT = new Object();

}

可以看出HashSet實現了Set接口,內部采用HashMap存儲元素,利用了HashMap的key不能重復的特性,實現元素去重。而value使用默認值,是一個空對象,沒有任何作用,純粹占坑。

初始化

HashSet常用的構造方法有兩個,有參構造方法,可以指定初始容量和負載系數。

/**
 * 無參構造方法
 */
HashSet<Integer> hashSet1 = new HashSet<>();

/**
 * 有參構造方法,指定初始容量和負載系數
 */
HashSet<Integer> hashSet = new HashSet<>(16, 0.75f);

再看一下構造方式對應的源碼實現:

/**
 * 無參構造方法
 */
public HashSet() {
    map = new HashMap<>();
}

/**
 * 有參構造方法,指定初始容量和負載系數
 */
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}

HashSet的構造方式源碼也很簡單,都是利用的HashMap的構造方法實現。

常用方法源碼

再看一下HashSet常用方法源碼實現:

/**
 * 添加元素
 */
public boolean add(E e) {
    return map.put(e, PRESENT) == null;
}

/**
 * 刪除元素
 */
public boolean remove(Object o) {
    return map.remove(o) == PRESENT;
}

/**
 * 判斷是否包含元素
 */
public boolean contains(Object o) {
    return map.containsKey(o);
}

/**
 * 迭代器
 */
public Iterator<E> iterator() {
    return map.keySet().iterator();
}

HashSet方法源碼也很簡單,都是利用HashMap的方法實現邏輯。利用HashMap的key不能重復的特性,value使用默認值,contains()方法和iterator()方法也都是針對key進行操作。

LinkedHashSet源碼實現

類屬性

LinkedHashSet繼承自HashSet,沒有任何私有的屬性。

public class LinkedHashSet<E>
        extends HashSet<E>
        implements Set<E>, Cloneable, java.io.Serializable {
}

初始化

LinkedHashSet常用的構造方法有三個,有參構造方法,可以指定初始容量和負載系數。

/**
 * 無參構造方法
 */
Set<Integer> linkedHashSet1 = new LinkedHashSet<>();

/**
 * 有參構造方法,指定初始容量
 */
Set<Integer> linkedHashSet2 = new LinkedHashSet<>(16);

/**
 * 有參構造方法,指定初始容量和負載系數
 */
Set<Integer> linkedHashSet3 = new LinkedHashSet<>(16, 0.75f);

再看一下構造方法的源碼實現:

/**
 * 無參構造方法
 */
public LinkedHashSet() {
    super(16, .75f, true);
}

/**
 * 有參構造方法,指定初始容量
 */
public LinkedHashSet() {
    super(16, .75f, true);
}

/**
 * 有參構造方法,指定初始容量和負載系數
 */
public LinkedHashSet(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor, true);
}

LinkedHashSet的構造方法使用的是父類HashSet的構造方法,而HashSet的構造方法使用的是LinkedHashMap的構造方法,設計的就是這么亂!

public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable {

    /**
     * HashSet的構造方法,底層使用的是LinkedHashMap,專門給LinkedHashSet使用
     *
     * @param initialCapacity 初始容量
     * @param loadFactor      負載系數
     * @param dummy           這個字段沒啥用
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

}

LinkedHashSet的其他方法也是使直接用的父類HashSet的方法,就不用看了。

LinkedHashSet額外實現了按照元素的插入順序或者訪問順序進行迭代的功能,是使用LinkedHashMap的實現,不了解LinkedHashMap的,可以看一下上篇文章對LinkedHashMap的源碼解析。

TreeSet源碼實現

類屬性

public class TreeSet<E> extends AbstractSet<E>
        implements NavigableSet<E>, Cloneable, java.io.Serializable {

    /**
     * 用來存儲數據
     */
    private transient NavigableMap<E, Object> m;

    /**
     * value的默認值
     */
    private static final Object PRESENT = new Object();

}

TreeSet內部使用NavigableMap存儲數據,而NavigableMap是TreeMap的父類,后面在初始化NavigableMap的時候,會用TreeMap進行替換。而value使用默認空對象,與HashSet類似。

初始化

TreeSet有兩個構造方法,有參構造方法,可以指定排序方式,默認是升序。

/**
 * 無參構造方法
 */
TreeSet<Integer> treeSet1 = new TreeSet<>();

/**
 * 有參構造方法,傳入排序方式,默認升序,這里傳入倒序
 */
TreeSet<Integer> treeSet2 = new TreeSet<>(Collections.reverseOrder());

再看一下構造方法的源碼實現:

TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}

/**
 * 無參構造方法
 */
public TreeSet() {
    this(new TreeMap<E, Object>());
}

/**
 * 有參構造方法,傳入排序方式,默認升序,這里傳入倒序
 */
public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}

TreeSet的構造方法內部是直接使用的TreeMap的構造方法,是基于TreeMap實現的。

常用方法源碼

/**
 * 添加元素
 */
public boolean add(E e) {
    return m.put(e, PRESENT) == null;
}

/**
 * 刪除元素
 */
public boolean remove(Object o) {
    return m.remove(o) == PRESENT;
}

/**
 * 判斷是否包含元素
 */
public boolean contains(Object o) {
    return m.containsKey(o);
}

/**
 * 迭代器
 */
public Iterator<E> iterator() {
    return m.navigableKeySet().iterator();
}

TreeSet常用方法的底層實現都是使用的TreeMap的方法邏輯,就是這么偷懶。

TreeSet可以按元素大小順序排列的功能,也是使用TreeMap實現的,感興趣的可以看一下上篇文章講的TreeMap源碼。由于TreeSet可以元素大小排列,所以跟其他Set集合相比,增加了一些按照元素大小范圍查詢的方法。

其他方法列表:

作用

方法簽名

獲取第一個元素

E first()

獲取最后一個元素

E last()

獲取大于指定鍵的最小鍵

E higher(E e)

獲取小于指定鍵的最大元素

E lower(E e)

獲取大于等于指定鍵的最小鍵

E ceiling(E e)

獲取小于等于指定鍵的最大鍵

E floor(E e)

獲取并刪除第一個元素

E pollFirst()

獲取并刪除最后一個元素

E pollLast()

獲取前幾個元素(inclusive表示是否包含當前元素)

NavigableSetheadSet(E toElement, boolean inclusive)

獲取后幾個元素(inclusive表示是否包含當前元素)

NavigableSettailSet(E fromElement, boolean inclusive)

獲取其中一段元素集合(inclusive表示是否包含當前元素)

NavigableSetsubSet(E fromElement, boolean fromInclusive, E toElement,   boolean toInclusive)

獲取其中一段元素集合(左開右開)

SortedSetsubSet(E fromElement, E toElement)

獲取前幾個元素(不包含當前元素)

SortedSetheadSet(E toElement)

獲取后幾個元素(不包含當前元素)

SortedSettailSet(E fromElement)

總結

HashSet、LinkedHashSet、TreeSet,這三個常用的Set集合的共同點是都實現了Set接口,所以使用方式都是一樣的,使用add()方法添加元素,使用remove()刪除元素,使用contains()方法判斷元素是否存在,使用iterator()方法迭代遍歷元素,這三個類都可以去除重復元素。

不同點是:HashSet的關鍵特性:

  1. 是最基礎的Set集合,可以去除重復元素。
  2. HashSet是基于HashMap實現的,使用組合的方式,并非繼承。
  3. 利用了HashMap的key不重復的特性,而value是一個默認空對象,其他方法也都是使用HashMap實現。

LinkedHashSet的關鍵特性:

  1. LinkedHashSet繼承自HashSet,而內部則是采用組合LinkedHashMap的方式實現的。
  2. LinkedHashSet在HashSet功能基礎上,增加了按照元素插入順序或者訪問順序的迭代方式,代價是額外增加一倍的存儲空間。
  3. 方法內部都是使用LinkedHashMap實現的。

TreeSet的關鍵特性:

  1. TreeSet是基于TreeMap實現的,也是采用組合的方式。
  2. TreeSet在HashSet功能基礎上,可以保證按照元素大小順序排列,代價是查詢、插入、刪除接口的時間復雜度從O(1)退化到O(log n)。
  3. 方法內部都是使用TreeMap實現的。
責任編輯:武曉燕 來源: 一燈架構
相關推薦

2020-06-04 14:15:55

Java中BigDecimal函數

2018-09-29 15:34:34

JavaList接口

2016-05-04 10:36:42

iossdwebimage開發

2025-01-20 00:00:00

反射Java語言

2025-04-01 08:00:00

curl開發運維

2024-01-25 10:14:09

HashSetHashMapJava

2020-12-18 08:59:51

蘋果iCloud儲存照片

2025-02-14 08:30:49

SpringJava開發

2024-12-27 09:29:09

2023-11-01 13:48:00

反射java

2019-07-25 12:46:32

Java高并發編程語言

2024-03-06 08:15:03

@Autowired注入方式Spring

2021-05-21 12:36:16

限流代碼Java

2022-01-17 07:32:34

Java參數方法

2016-06-01 15:42:58

Hadoop數據管理分布式

2020-04-17 14:25:22

Kubernetes應用程序軟件開發

2022-07-26 00:00:22

HTAP系統數據庫

2014-04-17 16:42:03

DevOps

2012-05-02 10:47:51

JavaJava集合框架

2021-02-01 13:59:47

比特幣區塊鏈安全
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日日操夜夜操天天操 | 久久久久久亚洲 | 自拍在线 | 久久久蜜桃一区二区人 | 日韩小视频在线 | 久久国产精品久久久久久 | 日日夜夜天天 | 最新日韩av | 亚洲视频中文字幕 | 国产不卡视频 | 欧美黄页| 久久久久久久久久久久久9999 | 欧美在线一区二区三区 | 久久亚洲精品国产精品紫薇 | 久久一区二区三区免费 | 欧美激情综合色综合啪啪五月 | 亚洲精品视频一区 | 天天草狠狠干 | 精品一区二区三区不卡 | 国产精品不卡 | 91精品久久久久 | 国产亚韩 | 亚洲欧美日韩在线一区二区 | 97高清国语自产拍 | 久久久久国产成人精品亚洲午夜 | 亚洲福利片 | 青青草av在线播放 | 日韩在线视频免费观看 | 国产精品久久久久久久久久久免费看 | 亚洲一区二区在线播放 | av黄色在线观看 | 蜜桃av一区二区三区 | 精品欧美黑人一区二区三区 | 国产一区二区在线视频 | 精品中文视频 | 青青草av在线播放 | 国产中文字幕在线 | 久久成人人人人精品欧 | 精品二区| 亚洲一区视频在线 | 久久综合影院 |