Collection框架二
我們都知道,當(dāng)想要保存一組基本類(lèi)型數(shù)據(jù)時(shí),數(shù)組是最有效的保存方式,也是推薦使用這種方式的。但是數(shù)組是固有大小的,當(dāng)運(yùn)行時(shí)才知道大小的程序,這種方式使用就受限制了,這就是Java容器類(lèi)產(chǎn)生的原因。Java集合類(lèi)有幾個(gè)特點(diǎn):首先,這種容器是高性能的,對(duì)基本數(shù)據(jù)集合(動(dòng)態(tài)數(shù)組、鏈接表、樹(shù)和散列表)的實(shí)現(xiàn)是高效率的。第二,容器類(lèi)允許不同類(lèi)型的類(lèi)集合以相同的方式和高度互操作方式工作。第三,容器類(lèi)是容易擴(kuò)展或修改的。容器類(lèi)的常用的基本類(lèi)型有List、Set和Map,這些對(duì)象類(lèi)型也稱(chēng)為集合類(lèi),但是在Java中使用了Collection這個(gè)名字來(lái)指代該類(lèi)庫(kù)的一個(gè)特殊子集,所以業(yè)界使用了范圍更廣泛的“容器”來(lái)稱(chēng)呼。Collection:是一個(gè)接口,它位于集合框架層次結(jié)構(gòu)的頂層,繼承自Iterable接口,說(shuō)明是可以用Iterator迭代器來(lái)訪問(wèn)該集合中的元素的。又有List、Set和Queue接口繼承Collection接口,直接實(shí)現(xiàn)該接口的是一個(gè)叫AbstractCollection的抽象類(lèi),該抽象類(lèi)以最大限度地減少了實(shí)現(xiàn)此接口所需的工作。
List:繼承自Collection接口,表示有序的、可包括重復(fù)元素的列表。同時(shí)擁有Collection內(nèi)的方法外,還添加了大量的方法,使得可以在List的中間插入和刪除元素。實(shí)現(xiàn)該接口的基本類(lèi)有ArrayList和LinkedList. ArrayList:擅長(zhǎng)于對(duì)元素的隨機(jī)訪問(wèn),但是在插入和刪除元素時(shí)效率較慢。其實(shí),看看ArrayList類(lèi)實(shí)現(xiàn)的源代碼就知道,ArrayList是以線性表的數(shù)據(jù)結(jié)構(gòu)形式存取數(shù)據(jù)的,初始化的表大小為10,下面就有幾個(gè)經(jīng)常用到的核心方法:add(E e):在當(dāng)前表的末尾插入元素,如果在前面表不滿(mǎn)的情況下,也是很高效的,直接插入到末尾,但是如果在當(dāng)前表已經(jīng)滿(mǎn)的情況下,就要重新生成一個(gè)比當(dāng)前表大小更大的新表,新表的大小是當(dāng)前表大小的1.5倍加1,比如當(dāng)前表長(zhǎng)度為20的,新表的大小就為31,還需要把當(dāng)前表元素復(fù)制到新表中去,然后把當(dāng)前表引用指向新表,最后把數(shù)值插入到表末尾,所以這種操作是非常低效的。
add(int index,E element):在指定索引位置插入元素,檢查表大小和重新追加表大小和上面的add(E e)方式是一樣的。最后是要把index以后的元素都是要依次往后移一個(gè)大小,然后把元素插入到index位置上去。涉及到表的復(fù)制和表內(nèi)元素的移動(dòng),所以效率也是比add(E e)方法還要低。
remove(int index):在指定索引位置刪除元素,就是把index位置后的所有元素都往前移一個(gè)大小,也是涉及到表內(nèi)元素的移動(dòng),效率也是很低的。
remove(Object o):刪除指定的元素,也就需要查找出該元素在表中出現(xiàn)第一次的位置,查找是用到順序一個(gè)一個(gè)進(jìn)行匹配的方法,找出后就把該元素后面的所有元素往前移一個(gè)大小。該方法涉及到順序查找和表內(nèi)元素移動(dòng),比remove(int index)方法更低效。
set(int index,E element):替換表中索引為index的元素值,返回被替換的值,直接用下標(biāo)索引訪問(wèn)元素,所以效率非常高。
get(int index):獲取索引為index的元素,直接用下標(biāo)索引訪問(wèn),所以效率也是非常高。
indexOf(Object o):獲取元素的索引號(hào),也就是需要查找,雖然用到了順序查找法,但效率還是比較高的。
LinkedList:擅長(zhǎng)于對(duì)元素的插入和刪除操作,但對(duì)于隨機(jī)訪問(wèn)元素比較慢。該類(lèi)的實(shí)現(xiàn)是以雙向鏈表的數(shù)據(jù)結(jié)構(gòu)為基礎(chǔ)的,所以是比較消耗內(nèi)存的,但它的特定集比ArrayList更大。雙向鏈表,每個(gè)節(jié)點(diǎn)都有三個(gè)域,兩個(gè)域是存放前后節(jié)點(diǎn)的內(nèi)存地址引用的,一個(gè)域是存放數(shù)據(jù)元素的。在LinkedList類(lèi)中,有一個(gè)叫Entry的內(nèi)部類(lèi),是private的,里面三個(gè)屬性,分別是element、next和previous,分別對(duì)應(yīng)了雙向鏈表中的三個(gè)域,在ArrayList類(lèi)中每實(shí)例化一個(gè)Entry就生成一個(gè)節(jié)點(diǎn)。下面看看它的核心方法:add(E e):把元素插入到鏈表末尾,首先要實(shí)例化一個(gè)節(jié)點(diǎn),新節(jié)點(diǎn)previous域存放鏈表中最后一個(gè)節(jié)點(diǎn)地址,next域存放鏈表中第一個(gè)節(jié)點(diǎn)地址,element域存放元素值,鏈表中最后一個(gè)節(jié)點(diǎn)的next域存放新節(jié)點(diǎn)的地址,第一個(gè)元素的previous域存放新節(jié)點(diǎn)的地址,這樣這個(gè)元素就插入到該鏈表中去了,沒(méi)有涉及到復(fù)雜的操作,所以是非常高效的。
add(int index,E element):在index位置插入元素,這就需要先查找到該位置。查到后,這里就把查到的節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)叫為A,實(shí)例化新的節(jié)點(diǎn)為B,查到index的節(jié)點(diǎn)為C.B的next域等于A的next值(也就是C的內(nèi)存地址),B的previous域等于C的previous值(也就是A的內(nèi)存地址),B的element域存放元素值,然后把A的next域和C的previous域都等于B的內(nèi)存地址。這樣也就把元素插入到鏈表的index位置中去了,但涉及到了查詢(xún),所以效率雖然高,但也沒(méi)有add(E e)那么高。
remove(int index):刪除在index位置的元素,首先也是要找到該位置的節(jié)點(diǎn)。然后把該節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)(也就是該節(jié)點(diǎn)next域的內(nèi)存地址那個(gè)節(jié)點(diǎn))的previous值等于該節(jié)點(diǎn)的previous值,該節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)(也就是該節(jié)點(diǎn)previous域的內(nèi)存地址那個(gè)節(jié)點(diǎn))的next值等于該節(jié)點(diǎn)的next值。這樣就把該節(jié)點(diǎn)從這條鏈表刪除了,過(guò)程中雖然涉及到了查找,但沒(méi)有涉及到像ArrayList類(lèi)中的remove方法要移動(dòng)表中元素,所以該方法的效率還是很高的。
remove(Object o):刪除在鏈表中第一個(gè)元素為o的節(jié)點(diǎn),也是需要查找到該節(jié)點(diǎn),然后就跟remove(int index)思路一樣把元素刪除,所以效率也是很高的。
set(int index,E element):把在鏈表中第index個(gè)元素值改為element,這也需要找到該節(jié)點(diǎn)來(lái)修改元素值,但涉及到了查找節(jié)點(diǎn),ArrayList中的set方法就不用查找就可以修改,所以相對(duì)于ArrayList中的set方法,LinkedList方法set方法效率就沒(méi)那么高了。
get(int index):獲取第index位置的元素值,也是要找到該節(jié)點(diǎn),所以就也沒(méi)ArrayList中的get方法那么高效率了,因?yàn)樵摲椒ㄐ枰檎益湵怼?/p>
indexOf(Object o):獲取該鏈表中第一o元素的位置,也是要查找鏈表,但ArrayList中的indexOf方法也是需要查找的,所以這兩個(gè)類(lèi)的indexOf的效率都差不多。
所以,在編程中,如果要進(jìn)行大量的隨機(jī)訪問(wèn),就使用ArrayList;如果要經(jīng)常從表中插入或刪除元素的就應(yīng)該使用LinkedList.
Set:繼承自Collection接口,表示無(wú)序的,無(wú)重復(fù)元素的集合。Set中最常使用的是測(cè)試歸屬性,可以很容易測(cè)試某個(gè)對(duì)象是否在某個(gè)Set中。所以,查找就成為了Set中最重要的操作,因此通常會(huì)選擇一個(gè)HashSet的實(shí)現(xiàn)查找,因?yàn)橛斜容^復(fù)雜的哈希表支持,它專(zhuān)門(mén)對(duì)快速查找進(jìn)行了優(yōu)化。
迭代器:迭代器是一種設(shè)計(jì)模式,在這里是一個(gè)對(duì)象,它的作用就是遍歷并選擇列表和操作列表中的對(duì)象。迭代器的創(chuàng)佳的代價(jià)小,所以通常被稱(chēng)為輕量級(jí)對(duì)象。迭代器統(tǒng)一了對(duì)各種容器的訪問(wèn)方式,很方便。Java中的迭代器有兩種,一種是Iterator,另一種是繼承了Iterator只能用于各種List訪問(wèn)的ListIterator. Iterator:只能用于單向移動(dòng),方法有:iterator()要求容器返回一個(gè)Iterator,Iterator將準(zhǔn)備好返回序列的第一元素。next()獲得列表中的下一個(gè)元素。hasNext()檢查列表中是否還有元素。remove()將迭代器新近返回的元素刪除。
ListIterator:只能用于各種的List類(lèi)的訪問(wèn),但能用于雙向的移動(dòng),有一個(gè)hasPrevious()檢查時(shí)候有前一個(gè)元素的,這種操作很像數(shù)據(jù)庫(kù)的游標(biāo)。
import java.util.ArrayList; public class ListTest ...{ |
Map:也是一個(gè)映射存儲(chǔ)鍵/值對(duì)的接口,但跟Collection沒(méi)有任何關(guān)系的,也沒(méi)有繼承任何接口,所以不能用Iterator迭代器來(lái)訪問(wèn)該集合中的元素。給定一個(gè)關(guān)鍵字和一個(gè)值,可以存儲(chǔ)這個(gè)值到一個(gè)Map對(duì)象中,存儲(chǔ)以后,就可以使用它的關(guān)鍵字來(lái)檢索它。映射經(jīng)常使用到的兩個(gè)基本操作:get()和put()。使用put()方法可以將一個(gè)指定了關(guān)鍵字和值的項(xiàng)加入映射。為了得到值,可以通過(guò)將關(guān)鍵字作為參數(shù)來(lái)調(diào)用get()方法。
import java.util.HashMap; public class TestMap ...{ |
posted on 2008-04-17 16:43 forgood 閱讀(556) 評(píng)論(1) 編輯 收藏