集合框架:
程序開(kāi)發(fā)并不是解決了業(yè)務(wù)的基本功能就完成了馅而,很多時(shí)候程序運(yùn)行的環(huán)境是有限制的。比如內(nèi)存小唤崭,CPU頻率低,或者是像手機(jī)這樣的設(shè)備超陆,能源供應(yīng)有限。在這種環(huán)境下浦马,就需要程序能夠在有限的環(huán)境中提升效率时呀。這就需要使用數(shù)據(jù)結(jié)構(gòu)和算法。
但是數(shù)據(jù)結(jié)構(gòu)與算法即便是學(xué)過(guò)捐韩,也未必在工作時(shí)能夠用好退唠,而且通用性鹃锈、性能等等也都是問(wèn)題荤胁。加上學(xué)習(xí)程序開(kāi)發(fā)的受眾群體越來(lái)越廣,讓程序員全部自己實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)與算法不是一個(gè)好的主意屎债。所以現(xiàn)在很多語(yǔ)言為了能夠提升學(xué)習(xí)效率仅政,降低學(xué)習(xí)門(mén)檻,同時(shí)也為了讓程序有更好的執(zhí)行效率和通用性盆驹,就自帶了各種實(shí)現(xiàn)了數(shù)據(jù)結(jié)構(gòu)與算法的API集合圆丹。在Java中,這就是我們現(xiàn)在要學(xué)習(xí)的「集合框架」
與現(xiàn)在常見(jiàn)到的數(shù)據(jù)結(jié)構(gòu)類(lèi)庫(kù)一樣躯喇,Java也是將集合類(lèi)庫(kù)的接口(interface)與實(shí)現(xiàn)(implementation)分離辫封。所以我們的學(xué)習(xí)方式一般都是先搞明白接口的分類(lèi)和關(guān)系硝枉,然后根據(jù)不同的接口來(lái)學(xué)習(xí)對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)。
## 使用集合做什么
搬運(yùn)數(shù)據(jù)倦微,集合可以存儲(chǔ)數(shù)據(jù)妻味,然后通過(guò)API調(diào)用很方便就可以傳遞大量數(shù)據(jù)
數(shù)據(jù)處理,集合中可以直接對(duì)數(shù)據(jù)進(jìn)行操作欣福,比如統(tǒng)計(jì)责球、去重
-
排序,可以將數(shù)據(jù)按照需求進(jìn)行各種排序拓劝,然后再傳遞給調(diào)用者
集合的分類(lèi):
Java的集合從 Collection 接口和 Map 接口入手
Map 接口和 Collection 沒(méi)有交集雏逾,它有自己的方式,只要標(biāo)準(zhǔn)庫(kù)后綴不是Map 結(jié)尾的郑临,都是直接或者間接實(shí)現(xiàn)了Collection接口栖博。
Collection 接口中常見(jiàn)的操作是數(shù)據(jù)的添加、刪除
- add / addAll
- remove / removeAll / removeIf
借助 Iterator 接口牧抵,Collection 還具備了數(shù)據(jù)的循環(huán)笛匙。
public interface Collection<E> extends Iterable<E>{
//...
// 對(duì)數(shù)據(jù)循環(huán)
Iterator<E> iterator();
}```
通過(guò) Iterable 接口, 標(biāo)準(zhǔn)庫(kù)中的集合都可以使用 forEach 循環(huán)犀变。
具體的實(shí)現(xiàn)類(lèi)
集合類(lèi)型 | 描述 |
---|---|
ArrayList | 一種可以動(dòng)態(tài)增長(zhǎng)和縮減的索引序列 |
LinkedList | 一種可以在任何位置進(jìn)行高效地插人和刪除操作的有序序列 |
ArrayDeque | 一種用循環(huán)數(shù)組實(shí)現(xiàn)的雙端隊(duì)列 |
HashSet | 一種沒(méi)有重復(fù)元素的無(wú)序集合 |
TreeSet | 一種有序集 |
EnumSet | 一種包含枚舉類(lèi)型值的集 |
LinkedHashSet | 一種可以記住元素插人次序的集 |
PriorityQueue | 一種允許高效刪除最小元素的集合 |
HashMap | 一種存儲(chǔ)鍵/ 值關(guān)聯(lián)的數(shù)據(jù)結(jié)構(gòu) |
TreeMap | 一種鍵值有序排列的映射表 |
EnumMap | 一種鍵值屬于枚舉類(lèi)型的映射表 |
LinkedHashMap | 一種可以記住腱/ 值項(xiàng)添加次序的映射表 |
WeakHashMap | 一種其值無(wú)用武之地后可以被垃圾回收器回收的映射表 |
IdentityHashMap | 一種用 == 而不是用equals 比較鍵值的映射表 |
Collection
Map
雖然類(lèi)很多 妹孙,但是我們?cè)诮淌谥兄恍枰粠讉€(gè)類(lèi)就可以了,分別是下面:
- ArrayList
- LinkedList
- HashSet
- HashMap
- TreeMap
然后加上工具類(lèi)2個(gè):
- Collections
- Arrays
List
有序集合获枝,可以精確控制列表中每個(gè)元素的插入位置蠢正。通過(guò)整數(shù)索引獲取列表中的元素。List允許出現(xiàn)重復(fù)的值 省店, 并可以精確控制列表中每個(gè)元素的插入位置嚣崭,通過(guò)整數(shù)索引獲取列表中的元素。
方法名 | 說(shuō)明 |
---|---|
add(E e) | 增加單個(gè)數(shù)據(jù) |
addAll(Collection<? extends E> c) | 將一個(gè) Collection 集合的數(shù)據(jù)添加到現(xiàn)在的集合中 |
remove(Object o) | 刪除指定的元素 |
contains(Object o) | 判斷集合是否包含指定的元素 |
size() | 得到集合的數(shù)據(jù)總數(shù) |
isEmpty() | 判斷集合是否有數(shù)據(jù) |
get(int index) | 通過(guò)索引獲取對(duì)應(yīng)的數(shù)據(jù)元素 |
set(int index, E element) | 通過(guò)索引和新的元素替換原有內(nèi)容 |
clear() | 清空數(shù)據(jù) |
toArray() | 將List轉(zhuǎn)為對(duì)象數(shù)組 |
ArrayList:
ArrayList 是List 接口的大小可變數(shù)組的實(shí)現(xiàn)懦傍。實(shí)現(xiàn)了所有可選列表操作雹舀, 并允許包括null 在內(nèi)的所有元素。除了實(shí)現(xiàn)List 接口外粗俱, 此類(lèi)還提供一些方法來(lái)操作內(nèi)部用來(lái)存儲(chǔ)列表的數(shù)組的大兴涤堋( 此類(lèi)大致上等同于 vector 類(lèi), 但 vector 是同步的) 寸认。
ArrayList 的底層是使用數(shù)組實(shí)現(xiàn)的签财,看下面的圖:
可以看到,數(shù)組中的每一個(gè)元素偏塞,都存儲(chǔ)在內(nèi)存單元中唱蒸,并且元素之間緊密排列,既不能打亂元素的存儲(chǔ)順序灸叼,也不能跳過(guò)某個(gè)存儲(chǔ)單元進(jìn)行存儲(chǔ)神汹。
ArrayList 底層既然是使用數(shù)組實(shí)現(xiàn)庆捺,那么特點(diǎn)就和數(shù)組一致:查詢速度快,增刪速度慢
每個(gè)ArrayList 實(shí)例都有一個(gè)容量屁魏。該容量是指用來(lái)存儲(chǔ)列表元素的數(shù)組的大小疼燥, 它總是至少等于列表的大小。隨著向Array L ist 中小斷添加元素蚁堤, 其容量也自動(dòng)增長(zhǎng)醉者。并未指定增長(zhǎng)策略的細(xì)節(jié),因?yàn)檫@不只是添加元素會(huì)帶來(lái)分?jǐn)偣潭〞r(shí)間開(kāi)銷(xiāo)那樣簡(jiǎn)單披诗。我們可以使用默認(rèn)構(gòu)造函數(shù)創(chuàng)建容量為 10 的列表撬即, 也可以初始化指定容量大小。
ArrayList 指定初始容量大小的構(gòu)造器方法
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}```
常用的操作
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
// 添加數(shù)據(jù)
list.add(123);
list.add(346);
// 替換數(shù)據(jù)
list.set(1, 777);
// 將list中的所有數(shù)據(jù)放到 list2 中
List<Integer> list2 = new ArrayList<>();
list2.addAll( list );
// 循環(huán)list2中所有的數(shù)據(jù)
for (Integer integer : list2) {
System.out.println( integer );
// 刪除循環(huán)出的對(duì)象
list2.remove(integer);
}
// list 集合是否有數(shù)據(jù)
if( !list.isEmpty() ) {
System.out.println("list.size = "+ list.size());
// 清空 list
list.clear();
}
// 在清空l(shuí)ist后呈队,再看list現(xiàn)在有多少數(shù)據(jù)
System.out.println("list.size = "+ list.size());
}