在Java中有許多的容器集合。初一看起來有些糊涂,特別是對剛接觸Java來說(至少我當初就是這樣的)!其實稍微細心,深入一點點就會發(fā)現(xiàn)原來一切都是有規(guī)律的。我想別的事情也會是如此。
Java中的容器,接口都是由一些接口,抽象類及它們的實現(xiàn)類所組成。而它們?nèi)糠庋b在java.util
包中。
1:Collection接口。
大多數(shù)的集合都實現(xiàn)了此接口,它基本方法是add(沒有g(shù)et()方法,實現(xiàn)類中可能有如Arrylist),添加一對象。添加成功則返回true ,否則返回false。這是與Map不同的地方。還有一些常用的方法如iterator(),size(),toArray()(注:toArray()是返回一對象----object數(shù)組,而Arrays----也是java.util下的一個類,有一個asList方法它們通常認為是各集合之間轉(zhuǎn)換的橋梁)等等!具體用法可以參考API文檔。
2:Map(映射)
Map接口跟Collection接口實際上沒有半點關(guān)系。集合中的每一個元素都包含一對鍵對對象和值對象,集合中沒有重復的鍵對象,值對象可以重復。它的有些實現(xiàn)類能對集合中的鍵對象進行排序。與Collection截然不同的是,它其中所存取的是一些值與名相對應(yīng)的數(shù)據(jù)。也就是一個Key對應(yīng)一個Value的方式來存儲。所以它就有與之對應(yīng)的一些方法如:put (K key, V value)等等,更多可以參考API文檔。
3:List(列表)
集合中的對象按索引位置排序,可以有重復對象,允許按照對象在集合中的索引位置檢索對象
4:Set(集)
集合中的對象中按特定的方式排序,并且沒有重復對象。它的有些實現(xiàn)類能對集合中的對象
按特定的方式排序
5:迭代器:Iterator
它是一個接口,只有三個方法hasnext(),next(),remove()只有最后一個是可選的,也就是remove()是可選(在實現(xiàn)的時候)。其可選性也意味著它的實現(xiàn)類中,remove方法是可有可無的。例如,若有一個如下的List 實例。
Arrylist al = new Arrylist();
Object[] ob = al.toArray();
List list = Arrays.asList(ob);
Iterator itor = list.iterator();
itor.remove(); //Error
當調(diào)用Ierator itr = list.iterator()方法返回一迭代器的時候,便不支持remove方法,所以當你再使用irt.remove()時程序就是異常!
使用此迭代器要注意的是remove()方法。它所刪除的是指指針(暫這么叫著)上次所移經(jīng)過的位置(Removes from the underlying collection the last element returned by the iterator (optional operation).)。我個人覺得有點象在JDBC中的ResultSet rs = ....;rs.last();rowsCount=rs.getRow();類似呢。
前面所講的,由于clollection提供了iterator()方法,所以迭代器是很容易實現(xiàn)的!
6:常用實現(xiàn)類的一些繼承關(guān)系:
Collections,它是Java.util下的一個類。它為我們提供了許多有用的方法,如sort(...),max()等其具體用法可以參考API文檔,比如sort(List list);中l(wèi)ist內(nèi)的所有元素都必須實現(xiàn)Comparable接口(All elements in the list must implement the Comparable interface)。
Arrylist ,它是List接口的實現(xiàn)類,而List則是繼承于Collection。
LinkedList,它也是間接對Colections的實現(xiàn)。用linkedlist的一些方法如addfirst(),removefirst(),addlast()等等可以用來實現(xiàn)如C中的堆棧,鏈表。(對于頻繁使用插入與刪除操作使用linkedlist是個不錯的選擇,對于經(jīng)常進行索引操作則arrylist較好)。
HashSet(散列表),它實現(xiàn)了Set接口,也就意味著它的元素不能有重復值出現(xiàn)。并且在HashSet中沒有g(shù)et()方法,但可以通過iterator()來實現(xiàn)。要注意的是假如要在HasSet中存放一些對象,那么你得重定義hashCode()與equals()二個方法來保不可以存放相同的內(nèi)容的元素。對于hashcode()所返回的值,hashset用它來計算(通過特定的函數(shù))該對象在內(nèi)存中的存放位置;后者主要用來判斷二個對象的內(nèi)容是否相等而返回對應(yīng)的boolen型。
TreeSet,主要用來對元素進行排序操作,假如要往其中添加對象,則對象得實現(xiàn)Comparable接口。(假如不要對元素排序,則一般可選用HashSet)。
HashMap,主要特點是存放的一個鍵值對,一些有用的方法是可返回視圖(我覺得可以把它理解為一個集合)如:keyset(),values(),entyset()等。
關(guān)于對HashMap的小步深入理解:
HashMap是由鍵值對組成的,關(guān)于HashMap有二點要注意:1. 它的鍵只能是一個Object對象。 2. 當二個HashMap用equals方法比較時,實際的比較是它的Key,而與Value無關(guān)。
HashMap的主要特點是其底層的物理存放與查找用到了hash函數(shù)相關(guān)的原理。根據(jù)java窗口的查找原理,查找最快的應(yīng)該是由數(shù)組經(jīng)過工具類Arrays的Arrays.sort方法排序后,再用此工具類的Arrays.binarySearch方法進行查找。對于HashMap的數(shù)據(jù)查找就是用這個原理實現(xiàn)的,另外由于數(shù)組的致命缺點就是它是定長的,而HashMap卻是可以動態(tài)增加,所以查找過程其實不是將Key本身放在一個Object[]的數(shù)組中,而是將與Key有密切相關(guān)的信息做為索引Object[]數(shù)組的下標,然后根據(jù)此下標去Object[]數(shù)組中查找數(shù)據(jù),這個所謂密切相關(guān)的信息就是通過Key.hashCode()函數(shù)所產(chǎn)生的數(shù)字。可想而知,當HashMap中的Key很多時,各Key所產(chǎn)生的hashCode肯定會有重合的現(xiàn)象發(fā)生,為了防止此情況發(fā)生,所以根據(jù)這個索引在數(shù)組中得到的對象并不是最終要查找的數(shù)據(jù),查到的其實是一個list列表,在這列表中列出了由于HashMap中的Key通過散列后具有相同hashCode的全部對像。可以想像得到,這個列表中的對像應(yīng)該是相當少的。對于對Object[]數(shù)據(jù)下下標定位后,就得到了這個列表,接下來equals函數(shù)粉墨登場了,若能返回true則表示此對象已經(jīng)存在,這時HashMap會用新的值覆蓋舊值,若不存在則會做添加操作了。
在HashMap的初始化中,會涉及到二個比較重要的值,也是影響其性能的二個重要值:Object[]的長度(v1)、Object[]中實際已經(jīng)存放了多少object對象(v2)。在我們初始化HashMap時會有:HashMap(int initialCapacity, float loadFactor) 這個方法,initialCapacity表示object[]的初始化長度,loadFactor表示允許此在Object[]存放數(shù)據(jù)的百分比(loadFactor=v2/v1),系統(tǒng)默認的是0.75(也就是可以存放占object[]數(shù)組3/4的數(shù)據(jù))。當HashMap里的數(shù)據(jù)不斷增加時,它會自動地按數(shù)量級擴展Object[]的長度(應(yīng)該盡量阻止Object[]的自動增加,這樣不但消費資源對于以后的查找、插入操作也不利)。
HashMap結(jié)論:對于Key一定要實現(xiàn)hashCode() and equals方法,且盡量要讓hashCode散布得均勻。這樣才能充分利用Object[]數(shù)組,不然,會導致Object[]得不到充分利用,而在Object[index]具體對應(yīng)的對象list列表中存放很多Key對像,而在list中進行查找操作是比較耗時的。
根據(jù)以上原理,HashMap的簡單實現(xiàn):
import java.util.*;
import com.bruceeckel.util.*;
public class SimpleHashMap extends AbstractMap {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
private static final int SZ = 997;
private LinkedList[] bucket = new LinkedList[SZ];
public Object put(Object key, Object value) {
Object result = null;
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
LinkedList pairs = bucket[index];
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
public static void main(String[] args) {
SimpleHashMap m = new SimpleHashMap();
Collections2.fill(m, Collections2.geography, 25);
System.out.println(m);
}
} ///:~
TreeMap,它與HashMap差不多,不過是增加了對元素的排序功能,所以運行速度也就當然沒有hashmap來得快了。
以下是HashMap的一個實例(在對DB進行操作的時候很有用):
HashMap valueMap;
//this function just get key-value form DB ,defined by yourself
valueMap = commondb.getElementStringValues("COMMENT_ID", "content");
java.util.Set tempkeys = valueMap.entrySet();
java.util.Iterator keys = tempkeys.iterator();
while(keys.hasNext())
{
java.util.Map.Entry me=(java.util.Map.Entry)keys.next();
String value = me.getValue();
int key = me.getKey();
}
要注意的是entrySet()所返回的每一個元素都是Map.Entry類型的!(Returns a collection view of the mappings contained in this map. Each element in the returned collection is a Map.Entry.)
Properties,繼承于hashtable。這個東東相信我們比較的喜歡了(在i18n,ant中可以是常見得很),呵呵。它可以從外部導入屬性文件。文件中的鍵值都是String類型。just like this:
company=study
author=Jkallen
copyright=2005-2006
操作如下:
import java.util.*;
import java.io.*;
class PropTest
{
public static void main(String[] args)
{
/*Properties pps=System.getProperties();
pps.list(System.out);*/
Properties pps=new Properties();
try
{
pps.load(new FileInputStream("winsun.ini"));
Enumeration enum=pps.propertyNames();
while(enum.hasMoreElements())
{
String strKey=(String)enum.nextElement();
String strValue=pps.getProperty(strKey);
System.out.println(strKey+"="+strValue);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
其用法可以查看API文檔呢。
Java中的集合容器確實不少呢...其中有些我們也許一直都用不到,(我也是查看了些相關(guān)的資料再加上自己的一些想法整理了一下,希望對相關(guān)朋友有用!)可是重要的是知道我們在實現(xiàn)一個功能時應(yīng)該選用哪種集合類來實現(xiàn)就OK了。
參考資料:JDK1.5文檔,Think in Java,孫鑫/張孝祥JAVA資料
Java中的容器,接口都是由一些接口,抽象類及它們的實現(xiàn)類所組成。而它們?nèi)糠庋b在java.util
包中。
1:Collection接口。
大多數(shù)的集合都實現(xiàn)了此接口,它基本方法是add(沒有g(shù)et()方法,實現(xiàn)類中可能有如Arrylist),添加一對象。添加成功則返回true ,否則返回false。這是與Map不同的地方。還有一些常用的方法如iterator(),size(),toArray()(注:toArray()是返回一對象----object數(shù)組,而Arrays----也是java.util下的一個類,有一個asList方法它們通常認為是各集合之間轉(zhuǎn)換的橋梁)等等!具體用法可以參考API文檔。
2:Map(映射)
Map接口跟Collection接口實際上沒有半點關(guān)系。集合中的每一個元素都包含一對鍵對對象和值對象,集合中沒有重復的鍵對象,值對象可以重復。它的有些實現(xiàn)類能對集合中的鍵對象進行排序。與Collection截然不同的是,它其中所存取的是一些值與名相對應(yīng)的數(shù)據(jù)。也就是一個Key對應(yīng)一個Value的方式來存儲。所以它就有與之對應(yīng)的一些方法如:put (K key, V value)等等,更多可以參考API文檔。
3:List(列表)
集合中的對象按索引位置排序,可以有重復對象,允許按照對象在集合中的索引位置檢索對象
4:Set(集)
集合中的對象中按特定的方式排序,并且沒有重復對象。它的有些實現(xiàn)類能對集合中的對象
按特定的方式排序
5:迭代器:Iterator
它是一個接口,只有三個方法hasnext(),next(),remove()只有最后一個是可選的,也就是remove()是可選(在實現(xiàn)的時候)。其可選性也意味著它的實現(xiàn)類中,remove方法是可有可無的。例如,若有一個如下的List 實例。






當調(diào)用Ierator itr = list.iterator()方法返回一迭代器的時候,便不支持remove方法,所以當你再使用irt.remove()時程序就是異常!
使用此迭代器要注意的是remove()方法。它所刪除的是指指針(暫這么叫著)上次所移經(jīng)過的位置(Removes from the underlying collection the last element returned by the iterator (optional operation).)。我個人覺得有點象在JDBC中的ResultSet rs = ....;rs.last();rowsCount=rs.getRow();類似呢。
前面所講的,由于clollection提供了iterator()方法,所以迭代器是很容易實現(xiàn)的!
6:常用實現(xiàn)類的一些繼承關(guān)系:
Collections,它是Java.util下的一個類。它為我們提供了許多有用的方法,如sort(...),max()等其具體用法可以參考API文檔,比如sort(List list);中l(wèi)ist內(nèi)的所有元素都必須實現(xiàn)Comparable接口(All elements in the list must implement the Comparable interface)。
Arrylist ,它是List接口的實現(xiàn)類,而List則是繼承于Collection。
LinkedList,它也是間接對Colections的實現(xiàn)。用linkedlist的一些方法如addfirst(),removefirst(),addlast()等等可以用來實現(xiàn)如C中的堆棧,鏈表。(對于頻繁使用插入與刪除操作使用linkedlist是個不錯的選擇,對于經(jīng)常進行索引操作則arrylist較好)。
HashSet(散列表),它實現(xiàn)了Set接口,也就意味著它的元素不能有重復值出現(xiàn)。并且在HashSet中沒有g(shù)et()方法,但可以通過iterator()來實現(xiàn)。要注意的是假如要在HasSet中存放一些對象,那么你得重定義hashCode()與equals()二個方法來保不可以存放相同的內(nèi)容的元素。對于hashcode()所返回的值,hashset用它來計算(通過特定的函數(shù))該對象在內(nèi)存中的存放位置;后者主要用來判斷二個對象的內(nèi)容是否相等而返回對應(yīng)的boolen型。
TreeSet,主要用來對元素進行排序操作,假如要往其中添加對象,則對象得實現(xiàn)Comparable接口。(假如不要對元素排序,則一般可選用HashSet)。
HashMap,主要特點是存放的一個鍵值對,一些有用的方法是可返回視圖(我覺得可以把它理解為一個集合)如:keyset(),values(),entyset()等。
關(guān)于對HashMap的小步深入理解:
HashMap是由鍵值對組成的,關(guān)于HashMap有二點要注意:1. 它的鍵只能是一個Object對象。 2. 當二個HashMap用equals方法比較時,實際的比較是它的Key,而與Value無關(guān)。
HashMap的主要特點是其底層的物理存放與查找用到了hash函數(shù)相關(guān)的原理。根據(jù)java窗口的查找原理,查找最快的應(yīng)該是由數(shù)組經(jīng)過工具類Arrays的Arrays.sort方法排序后,再用此工具類的Arrays.binarySearch方法進行查找。對于HashMap的數(shù)據(jù)查找就是用這個原理實現(xiàn)的,另外由于數(shù)組的致命缺點就是它是定長的,而HashMap卻是可以動態(tài)增加,所以查找過程其實不是將Key本身放在一個Object[]的數(shù)組中,而是將與Key有密切相關(guān)的信息做為索引Object[]數(shù)組的下標,然后根據(jù)此下標去Object[]數(shù)組中查找數(shù)據(jù),這個所謂密切相關(guān)的信息就是通過Key.hashCode()函數(shù)所產(chǎn)生的數(shù)字。可想而知,當HashMap中的Key很多時,各Key所產(chǎn)生的hashCode肯定會有重合的現(xiàn)象發(fā)生,為了防止此情況發(fā)生,所以根據(jù)這個索引在數(shù)組中得到的對象并不是最終要查找的數(shù)據(jù),查到的其實是一個list列表,在這列表中列出了由于HashMap中的Key通過散列后具有相同hashCode的全部對像。可以想像得到,這個列表中的對像應(yīng)該是相當少的。對于對Object[]數(shù)據(jù)下下標定位后,就得到了這個列表,接下來equals函數(shù)粉墨登場了,若能返回true則表示此對象已經(jīng)存在,這時HashMap會用新的值覆蓋舊值,若不存在則會做添加操作了。
在HashMap的初始化中,會涉及到二個比較重要的值,也是影響其性能的二個重要值:Object[]的長度(v1)、Object[]中實際已經(jīng)存放了多少object對象(v2)。在我們初始化HashMap時會有:HashMap(int initialCapacity, float loadFactor) 這個方法,initialCapacity表示object[]的初始化長度,loadFactor表示允許此在Object[]存放數(shù)據(jù)的百分比(loadFactor=v2/v1),系統(tǒng)默認的是0.75(也就是可以存放占object[]數(shù)組3/4的數(shù)據(jù))。當HashMap里的數(shù)據(jù)不斷增加時,它會自動地按數(shù)量級擴展Object[]的長度(應(yīng)該盡量阻止Object[]的自動增加,這樣不但消費資源對于以后的查找、插入操作也不利)。
HashMap結(jié)論:對于Key一定要實現(xiàn)hashCode() and equals方法,且盡量要讓hashCode散布得均勻。這樣才能充分利用Object[]數(shù)組,不然,會導致Object[]得不到充分利用,而在Object[index]具體對應(yīng)的對象list列表中存放很多Key對像,而在list中進行查找操作是比較耗時的。
根據(jù)以上原理,HashMap的簡單實現(xiàn):
import java.util.*;
import com.bruceeckel.util.*;
public class SimpleHashMap extends AbstractMap {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
private static final int SZ = 997;
private LinkedList[] bucket = new LinkedList[SZ];
public Object put(Object key, Object value) {
Object result = null;
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
LinkedList pairs = bucket[index];
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(pair)) {
result = ((MPair)iPair).getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key) {
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
MPair match = new MPair(key, null);
ListIterator it = pairs.listIterator();
while(it.hasNext()) {
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet() {
Set entries = new HashSet();
for(int i = 0; i < bucket.length; i++) {
if(bucket[i] == null) continue;
Iterator it = bucket[i].iterator();
while(it.hasNext())
entries.add(it.next());
}
return entries;
}
public static void main(String[] args) {
SimpleHashMap m = new SimpleHashMap();
Collections2.fill(m, Collections2.geography, 25);
System.out.println(m);
}
} ///:~
TreeMap,它與HashMap差不多,不過是增加了對元素的排序功能,所以運行速度也就當然沒有hashmap來得快了。
以下是HashMap的一個實例(在對DB進行操作的時候很有用):












要注意的是entrySet()所返回的每一個元素都是Map.Entry類型的!(Returns a collection view of the mappings contained in this map. Each element in the returned collection is a Map.Entry.)
Properties,繼承于hashtable。這個東東相信我們比較的喜歡了(在i18n,ant中可以是常見得很),呵呵。它可以從外部導入屬性文件。文件中的鍵值都是String類型。just like this:



操作如下:



























其用法可以查看API文檔呢。
Java中的集合容器確實不少呢...其中有些我們也許一直都用不到,(我也是查看了些相關(guān)的資料再加上自己的一些想法整理了一下,希望對相關(guān)朋友有用!)可是重要的是知道我們在實現(xiàn)一個功能時應(yīng)該選用哪種集合類來實現(xiàn)就OK了。
參考資料:JDK1.5文檔,Think in Java,孫鑫/張孝祥JAVA資料