java集合類源碼分析之Set詳解
Set集合與List一樣,都是繼承自Collection接口,常用的實現(xiàn)類有HashSet和TreeSet。值得注意的是,HashSet是通過HashMap來實現(xiàn)的而TreeSet是通過TreeMap來實現(xiàn)的,所以HashSet和TreeSet都沒有自己的數(shù)據(jù)結(jié)構(gòu),具體可以歸納如下:
•Set集合中的元素不能重復(fù),即元素唯一
•HashSet按元素的哈希值存儲,所以是無序的,并且最多允許一個null對象
•TreeSet按元素的大小存儲,所以是有序的,并且不允許null對象
•Set集合沒有g(shù)et方法,所以只能通過迭代器(Iterator)來遍歷元素,不能隨機訪問
1.HashSet
下面給出HashSet的部分源碼,以理解它的實現(xiàn)方式。
static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
觀察源碼,我們知道HashSet的數(shù)據(jù)是存儲在HashMap的實例對象map中的,并且對應(yīng)于map中的key,而Object類型的引用PRESENT則是對應(yīng)于map中的value的一個虛擬值,沒有實際意義。聯(lián)想到HashMap的一些特性:無序存儲、key值唯一等等,我們就可以很自然地理解Set集合元素不能重復(fù)以及HashSet無序存儲的特性了。
下面從源代碼的角度來理解HashSet的基本用法:
•構(gòu)造器(四種)
1.HashSet() 空的構(gòu)造器,初始化一個空的HashMap
2.HashSet(Collection<? extends E> c) 傳入一個子集c,用于初始化HashMap
3.HashSet(int initialCapacity, float loadFactor) 初始化一個空的HashMap,并指定初始容量和加載因子
4.HashSet(int initialCapacity) 初始化一個空的HashMap,并指定初始容量
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
•插入元素
1.add(E e) 插入指定元素(調(diào)用HashMap的put方法實現(xiàn))
Set<String> hashSet = new HashSet<String>();
hashSet.add("D");
hashSet.add("B");
hashSet.add("C");
hashSet.add("A");
•查找元素
1.contains(Object o) 判斷集合中是否包含指定的元素(調(diào)用HashMap的containsKey方法實現(xiàn))
public boolean contains(Object o) {
return map.containsKey(o);
}
2.由于HashSet的實現(xiàn)類中沒有g(shù)et方法,所以只能通過迭代器依次遍歷,而不能隨機訪問(調(diào)用HashMap中keySet的迭代器實現(xiàn))
public Iterator<E> iterator() {
return map.keySet().iterator();
}
應(yīng)用示例:
Set<String> hashSet = new HashSet<String>();
hashSet.add("D");
hashSet.add("B");
hashSet.add("C");
hashSet.add("A");
for (Iterator iterator = hashSet.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
System.out.print(string+" ");
}//D A B C
•修改元素
由于HashMap中的key值不能修改,所以HashSet不能進行修改元素的操作
•刪除元素
1.remove(Object o) 刪除指定元素(調(diào)用HashMap中的remove方法實現(xiàn),返回值為true或者false)
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
2.clear() 清空元素(調(diào)用HashMap中的clear方法實現(xiàn),沒有返回值)
public void clear() {
map.clear();
}
2.TreeSet
TreeSet是SortedSet接口的唯一實現(xiàn)類。前面說過,TreeSet沒有自己的數(shù)據(jù)結(jié)構(gòu)而是通過TreeMap實現(xiàn)的,所以TreeSet也是基于紅黑二叉樹的一種存儲結(jié)構(gòu),所以TreeSet不允許null對象,并且是有序存儲的(默認升序)。
private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
上述源代碼中的NavigableMap是繼承自SrotedMap的一個接口,其實現(xiàn)類為TreeMap,因此TreeSet中的數(shù)據(jù)是通過TreeMap來存儲的,此處的PRESENT也是沒有實際意義的虛擬值。
下面從源代碼的角度來理解HashSet的基本用法:
•構(gòu)造器(四種)
1.TreeSet() 空的構(gòu)造器,初始化一個空的TreeMap,默認升序排列
2.TreeSet(Comparator<? super E> comparator) 傳入一個自定義的比較器,常常用于實現(xiàn)降序排列
3.TreeSet(Collection<? extends E> c) 傳入一個子集c,用于初始化TreeMap對象,默認升序
4.TreeSet(SortedSet<E> s) 傳入一個有序的子集s,用于初始化TreeMap對象,采用子集的比較器
public TreeSet() {
this(new TreeMap<E,Object>());
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
應(yīng)用示例
//自定義一個比較器,實現(xiàn)降序排列
Set<Integer> treeSet = new TreeSet<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// return 0; //默認升序
return o2.compareTo(o1);//降序
}
});
treeSet.add(200);
treeSet.add(120);
treeSet.add(150);
treeSet.add(110);
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
} //200 150 120 110
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(300);
list.add(120);
list.add(100);
list.add(150);
System.out.println(list); //[300, 120, 100, 150]
//傳入一個子集,默認升序排列
TreeSet<Integer> treeSet = new TreeSet<Integer>(list);
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
}//100 120 150 300
/*
* 傳入一個有序的子集,采用子集的比較器
* 注意子集的類型必須是SortedSet及其子類或者實現(xiàn)類,否則將采用默認的比較器
* 所以此處subSet的類型也可以是TreeSet。
*/
SortedSet<Integer> subSet = new TreeSet<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// return 0; //默認升序
return o2.compareTo(o1);//降序
}
});
subSet.add(200);
subSet.add(120);
subSet.add(150);
subSet.add(110);
for (Iterator iterator = subSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
} //200 150 120 110
System.out.println();
Set<Integer> treeSet = new TreeSet<Integer>(subSet);
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
}//200 150 120 110
System.out.println();
treeSet.add(500);
treeSet.add(100);
treeSet.add(105);
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
}//500 200 150 120 110 105 100
• 插入元素
1.add(E e) 插入指定的元素(調(diào)用TreeMap的put方法實現(xiàn))
2.addAll(Collection<? extends E> c) 插入一個子集c
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(300);
list.add(120);
list.add(100);
list.add(150);
System.out.println(list); //[300, 120, 100, 150]
Set<Integer> treeSet = new TreeSet<Integer>();
//插入一個子集,默認升序
treeSet.addAll(list);
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
}//100 120 150 300
•查找元素
1.contains(Object o) 判斷集合中是否包含指定對象(調(diào)用TreeMap的containsKey方法實現(xiàn))
2.與HashSet一樣,TreeSet的實現(xiàn)類中沒有g(shù)et方法,所以只能通過迭代器依次遍歷,而不能隨機訪問(調(diào)用TreeMap中keySet的迭代器實現(xiàn))。
•修改元素
TreeSet不能進行修改元素的操作,原因與HashSet一樣。
•刪除元素
1.remove(Object o) 刪除指定元素(調(diào)用TreeMap中的remove方法實現(xiàn),返回true或者false)
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
2.clear() 清空元素(調(diào)用TreeMap中的clear方法實現(xiàn),無返回值)
public void clear() {
m.clear();
}
應(yīng)用示例:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(300);
list.add(120);
list.add(100);
list.add(150);
System.out.println(list); //[300, 120, 100, 150]
Set<Integer> treeSet = new TreeSet<Integer>();
//插入一個子集,默認升序
treeSet.addAll(list);
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
}//100 120 150 300
System.out.println(treeSet.remove(100));//true
for (Iterator iterator = treeSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.print(integer+" ");
}//120 150 300
treeSet.clear();
System.out.println(treeSet.size());//0
至此,HashSet和TreeSet的存儲結(jié)構(gòu)及基本用法介紹完畢。
以上這篇java集合類源碼分析之Set詳解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java class文件格式之特殊字符串_動力節(jié)點Java學院整理
特殊字符串出現(xiàn)在class文件中的常量池中,本著循序漸進和減少跨度的原則, 首先把class文件中的特殊字符串做一個詳細的介紹, 然后再回過頭來繼續(xù)講解常量池,對java class 文件格式相關(guān)知識感興趣的的朋友一起學習吧2017-06-06
使用Java8?Stream流的skip?+?limit實現(xiàn)批處理的方法
Stream 作為 Java 8 的一大亮點,它與 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念這篇文章主要介紹了使用Java8?Stream流的skip?+?limit實現(xiàn)批處理,需要的朋友可以參考下2022-07-07
IntelliJ IDEA 2020.1.2激活工具下載及破解方法免費可用至2089年(強烈推薦)
這篇文章主要介紹了IntelliJ IDEA 2020.1.2激活工具下載及破解方法免費可用至2089年(強烈推薦),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
Spring事務(wù)管理中關(guān)于數(shù)據(jù)庫連接池詳解
事務(wù)的作用就是為了保證用戶的每一個操作都是可靠的,事務(wù)中的每一步操作都必須成功執(zhí)行,只要有發(fā)生異常就 回退到事務(wù)開始未進行操作的狀態(tài)。事務(wù)管理是Spring框架中最為常用的功能之一,我們在使用Spring Boot開發(fā)應(yīng)用時,大部分情況下也都需要使用事務(wù)2022-12-12
Java中Thread和Runnable創(chuàng)建線程的方式對比
本文主要介紹了Java中Thread和Runnable創(chuàng)建線程的方式對比,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
Spring注解驅(qū)動之BeanDefinitionRegistryPostProcessor原理解析
這篇文章主要介紹了Spring注解驅(qū)動之BeanDefinitionRegistryPostProcessor原理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09

