我們都知道當想要保存一組基本類型數據時數組是最有效的保存方式也是推薦使用這種方式的但是數組是固有大小的當運行時才知道大小的程序這種方式使用就受限制了這就是Java容器類產生的原因Java集合類有幾個特點首先這種容器是高性能的對基本數據集合(動態數組鏈接表樹和散列表)的實現是高效率的第二容器類允許不同類型的類集合以相同的方式和高度互操作方式工作第三容器類是容易擴展或修改的容器類的常用的基本類型有ListSet和Map這些對象類型也稱為集合類但是在Java中使用了Collection這個名字來指代該類庫的一個特殊子集所以業界使用了范圍更廣泛的容器來稱呼
Collection是一個接口它位於集合框架層次結構的頂層繼承自Iterable接口說明是可以用Iterator迭代器來訪問該集合中的元素的又有ListSet和Queue接口繼承Collection接口直接實現該接口的是一個叫AbstractCollection的抽象類該抽象類以最大限度地減少了實現此接口所需的工作
List繼承自Collection接口表示有序的可包括重復元素的列表同時擁有Collection內的方法外還添加了大量的方法使得可以在List的中間插入和刪除元素實現該接口的基本類有ArrayList和LinkedList ArrayList擅長於對元素的隨機訪問但是在插入和刪除元素時效率較慢其實看看ArrayList類實現的源代碼就知道ArrayList是以線性表的數據結構形式存取數據的初始化的表大小為下面就有幾個經常用到的核心方法add(E e)在當前表的末尾插入元素如果在前面表不滿的情況下也是很高效的直接插入到末尾但是如果在當前表已經滿的情況下就要重新生成一個比當前表大小更大的新表新表的大小是當前表大小的倍加比如當前表長度為的新表的大小就為還需要把當前表元素復制到新表中去然後把當前表引用指向新表最後把數值插入到表末尾所以這種操作是非常低效的
add(int indexE element)在指定索引位置插入元素檢查表大小和重新追加表大小和上面的add(E e)方式是一樣的最後是要把index以後的元素都是要依次往後移一個大小然後把元素插入到index位置上去涉及到表的復制和表內元素的移動所以效率也是比add(E e)方法還要低
remove(int index)在指定索引位置刪除元素就是把index位置後的所有元素都往前移一個大小也是涉及到表內元素的移動效率也是很低的
remove(Object o)刪除指定的元素也就需要查找出該元素在表中出現第一次的位置查找是用到順序一個一個進行匹配的方法找出後就把該元素後面的所有元素往前移一個大小該方法涉及到順序查找和表內元素移動比remove(int index)方法更低效
set(int indexE element)替換表中索引為index的元素值返回被替換的值直接用下標索引訪問元素所以效率非常高
get(int index)獲取索引為index的元素直接用下標索引訪問所以效率也是非常高
indexOf(Object o)獲取元素的索引號也就是需要查找雖然用到了順序查找法但效率還是比較高的
LinkedList擅長於對元素的插入和刪除操作但對於隨機訪問元素比較慢該類的實現是以雙向鏈表的數據結構為基礎的所以是比較消耗內存的但它的特定集比ArrayList更大雙向鏈表每個節點都有三個域兩個域是存放前後節點的內存地址引用的一個域是存放數據元素的在LinkedList類中有一個叫Entry的內部類是private的裡面三個屬性分別是elementnext和previous分別對應了雙向鏈表中的三個域在ArrayList類中每實例化一個Entry就生成一個節點下面看看它的核心方法add(E e)把元素插入到鏈表末尾首先要實例化一個節點新節點previous域存放鏈表中最後一個節點地址next域存放鏈表中第一個節點地址element域存放元素值鏈表中最後一個節點的next域存放新節點的地址第一個元素的previous域存放新節點的地址這樣這個元素就插入到該鏈表中去了沒有涉及到復雜的操作所以是非常高效的
add(int indexE element)在index位置插入元素這就需要先查找到該位置查到後這裡就把查到的節點的前一個節點叫為A實例化新的節點為B查到index的節點為CB的next域等於A的next值(也就是C的內存地址)B的previous域等於C的previous值(也就是A的內存地址)B的element域存放元素值然後把A的next域和C的previous域都等於B的內存地址這樣也就把元素插入到鏈表的index位置中去了但涉及到了查詢所以效率雖然高但也沒有add(E e)那麼高
remove(int index)刪除在index位置的元素首先也是要找到該位置的節點然後把該節點的下一個節點(也就是該節點next域的內存地址那個節點)的previous值等於該節點的previous值該節點的上一個節點(也就是該節點previous域的內存地址那個節點)的next值等於該節點的next值這樣就把該節點從這條鏈表刪除了過程中雖然涉及到了查找但沒有涉及到像ArrayList類中的remove方法要移動表中元素所以該方法的效率還是很高的
remove(Object o)刪除在鏈表中第一個元素為o的節點也是需要查找到該節點然後就跟remove(int index)思路一樣把元素刪除所以效率也是很高的
set(int indexE element)把在鏈表中第index個元素值改為element這也需要找到該節點來修改元素值但涉及到了查找節點ArrayList中的set方法就不用查找就可以修改所以相對於ArrayList中的set方法LinkedList方法set方法效率就沒那麼高了
get(int index)獲取第index位置的元素值也是要找到該節點所以就也沒ArrayList中的get方法那麼高效率了因為該方法需要查找鏈表
indexOf(Object o)獲取該鏈表中第一o元素的位置也是要查找鏈表但ArrayList中的indexOf方法也是需要查找的所以這兩個類的indexOf的效率都差不多
所以在編程中如果要進行大量的隨機訪問就使用ArrayList如果要經常從表中插入或刪除元素的就應該使用LinkedList
Set繼承自Collection接口表示無序的無重復元素的集合Set中最常使用的是測試歸屬性可以很容易測試某個對象是否在某個Set中所以查找就成為了Set中最重要的操作因此通常會選擇一個HashSet的實現查找因為有比較復雜的哈希表支持它專門對快速查找進行了優化
迭代器迭代器是一種設計模式在這裡是一個對象它的作用就是遍歷並選擇列表和操作列表中的對象迭代器的創佳的代價小所以通常被稱為輕量級對象迭代器統一了對各種容器的訪問方式很方便Java中的迭代器有兩種一種是Iterator另一種是繼承了Iterator只能用於各種List訪問的ListIterator Iterator只能用於單向移動方法有iterator()要求容器返回一個IteratorIterator將准備好返回序列的第一元素next()獲得列表中的下一個元素hasNext()檢查列表中是否還有元素remove()將迭代器新近返回的元素刪除
ListIterator只能用於各種的List類的訪問但能用於雙向的移動有一個hasPrevious()檢查時候有前一個元素的這種操作很像數據庫的游標
import javautilArrayList;
import javautilArrays;
import javautilCollection;
import javautilIterator;
import javautilLinkedList;
import javautilList;
import javautilListIterator;
public class ListTest {
public static void main(String [] args)
{
Collection<Integer> col = new ArrayList<Integer>(ArraysasList());
List<Integer> list = new LinkedList<Integer>();
listaddAll(col);
listadd();
listadd();
listadd();
displayIterator(list);
listremove();
displayListIterator(list);
}
public static void displayIterator(Collection<Integer> list)
{
Iterator<Integer> it = erator();
Integer i;
while(ithasNext())
{
i = itnext();
Systemoutprint(i + );
if(i==)
{
itremove();
}
}
Systemoutprintln();
}
public static void displayListIterator(List<Integer> list)
{
ListIterator<Integer> li = listlistIterator();
/** *//**以下注釋代碼為死循環永遠輸入表中的第一個數據*/
/** *//**while(lihasNext())
{
Systemoutprintln(linext());
Systemoutprintln(liprevious());
}*/
while(lihasNext())
{
Systemoutprint(linext() + );
}
Systemoutprintln();
while(lihasPrevious())
{
Systemoutprint(liprevious() + );
}
}
}
Map也是一個映射存儲鍵/值對的接口但跟Collection沒有任何關系的也沒有繼承任何接口所以不能用Iterator迭代器來訪問該集合中的元素給定一個關鍵字和一個值可以存儲這個值到一個Map對象中存儲以後就可以使用它的關鍵字來檢索它映射經常使用到的兩個基本操作get()和put()使用put()方法可以將一個指定了關鍵字和值的項加入映射為了得到值可以通過將關鍵字作為參數來調用get()方法
import javautilHashMap;
import javautilMap;
public class TestMap {
public static void main(String [] args)
{
Map<StringInteger> hm = new HashMap<StringInteger>();
hmput(a );
hmput(b );
hmput(c );
hmput(d );
hmput(e );
display(hm);
Systemoutprintln(ntainsKey(c));
hmremove(c);
Systemoutprintln(ntainsValue());
Systemoutprintln(hmsize());
}
public static void display(Map<StringInteger> m)
{
for(String s : mkeySet())
{
Systemoutprintln(s + : + mget(s));
}
}
}
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27415.html