當前位置:首頁 » Java教學 » Java集合類

Java集合類

Java集合類- Vector(矢量), BitSet(位集), Stack(堆棧), Hashtable(散列表)。

Java集合類

在寫程序的時候並不是每次隻使用一個對象, 更多的是對一組對象進行操作, 就需要知道如何組合這些對象, 還有在編碼的時候我們有時並不知道到底有多少對象,它們需要進行動態的分配存放。

Java的集合類隻能容納對象句柄, 對於簡單類型的數據存放, 隻能通過數據來存放, 數組可以存放簡單類型的數據也能存放對象。

Java提供了四種類型的集合類: Vector(矢量), BitSet(位集), Stack(堆棧), Hashtable(散列表)。

1.         矢量: 一組有序的元素, 可以通過index進行訪問。

2.         位集: 其實就是由二進製位構成的Vector, 用來保存大量”開-關”信息, 它所占的空間比較小, 但是效率不是很高, 如果想高效率訪問, 還不如用固定長度的數組。

3.         堆棧: 先入後出(LIFO)集合, java.util.Stack類其實就是從Vector繼承下來的, 實現了pop, push方法。

4.         散列表: 由一組組“鍵--值”組成, 這裡的鍵必須是Object類型。 通過Object的hashCode進行高效率的訪問。

對於這些集合之間的關聯關係見下圖, 其中標色的部分為我們常用的類。

由上圖可以看出, 基本接口有兩個:

Collection: 所有的矢量集合類都從它繼承下去的, 但並不直接從它繼承下去的。 List與Set這兩個接口直接繼承了Collection, 他們的區彆是List裡麵可以保存相同的對象句柄, 而Set裡麵的值是不重複的。 我們經常用的Vector與ArrayList就是從List繼承下去的, 而HashSet是從Set繼承的。

Map:散列表的接口, Hashtable與HashMap繼承了這個接口。

下麵給出常用集合類的常用方法。

/**

 * Vector 與 ArrayList的操作幾乎是一樣的

 * 常用的追加元素用add(), 刪除元素用remove()

 * 取元素用get(), 遍曆它可以循環用get()取. 或者

 * 先得到一個Iterator, 然後通過遍曆Iterator的方法

 * 遍曆Vector或ArrayList

 */

// 生成一個空的Vector

Vector vector = new Vector();

// 在最後追加一個元素。

vector.add("one");

vector.add("two");

// 在指定的地方設置一個值

vector.set(0, "new one");

// 移走一個元素或移走指定位置的元素

vector.remove(0);

// 用for循環遍曆這個Vector

for (int i = 0; i < vector.size(); i++) {

String element = (String) vector.get(i); }

// 用枚舉器(Enumeration)遍曆它(隻有Vector有,ArrayList冇有)

Enumeration enu = vector.elements();

while (enu.hasMoreElements()) {

enu.nextElement();}

// 用反複器(Iterator)遍曆它

Iterator it = vector.iterator();

while (it.hasNext()) {it.next();}

/**

 * Hashtable與HashMap的操作, 追加元素用put(不是add)

 * 刪除元素用remove, 遍曆可以用Iterator 既可以遍曆

 * 它的key, 也可以是value

 */

// 生成一個空的Hashtable或HashMap

Hashtable hashtable = new Hashtable();

// 追加一個元素

hashtable.put("one", "one object value");

// 刪除一個元素

hashtable.remove("one");

// 用Iterator遍曆

Iterator keyIt = hashtable.keySet().iterator();

while (keyIt.hasNext()) {

Object keyName = keyIt.next();

String value = (String) hashtable.get(keyName); }

Iterator valueIt = hashtable.values().iterator();

while (valueIt.hasNext()) {

valueIt.next();}


// 用Enumeration遍曆, 隻有Hashtable有, HashMap冇有.

Enumeration enu = hashtable.elements();

while (enu.hasMoreElements()) {

enu.nextElement();}


說明: Enumeration是老集合庫中的接口, 而Iterator是新集合(1.2)中出現的, 而Vector與Hashtable也都是老集合中的類, 所以隻有Vector與Hashtable可以用Enumeration。


Vector與ArrayList對比:

雖然在使用的時候好象這兩個類冇什麼區彆, 它們都是從List繼承下來的, 擁有相同的方法, 但它們的內部還是有些不同的,

Ø         首先Vector在內部的一些方法作了線程同步(synchronized)。 同步的代價就是降低了執行效率, 但提高了安全性。而ArrayList則是線程不同步的, 可以多線程並發讀寫它。

Ø         內部數據增長率。 所有的這些矢量集合在內部都是用Object的數組進行存儲和操作的。 所以也就明白了為什麼它可以接受任何類型的Object, 但取出來的時候需要進行類型再造。 Vector與ArrayList具有自動伸縮的功能, 我們不用管它size多大, 我們都可以在它的後麵追加元素。 Vector與ArrayList內部的數組增長率是不一樣的, 當內部的數組不能容納更多元素的時候, Vector會自動增長到原兩倍大小, ArrayList會變為原一倍半大小, 而不是我們所想象的一個元素一個元素的增長。


Hashtable與HashMap對比:

Hashtable與HashMap都是從Map繼承下來的, 方法幾乎都一樣, 它們內部有兩個不同點:

Ø         與Vector和ArrayList一樣, 它們在線程同步是不同的, Hashtable在內部做了線程同步, 而HashMap是線程不同步的。

Ø         HashMap的鍵與值都可以為null, 而Hashtable不可以, 如果你試圖將一個null值放到Hashtable裡麵去, 會拋一個NullPointException的。


性能對比:

拋開不常用的集合不講, 每種集合都應該有一個我們常用的集合類, 而在不同的場合下應該使用效率最高的一個。 一般來說我推薦儘量使用新的集合類, 除非不得已, 比如說需要用用了老集合類寫的產品的程序。 也就是說儘量使用ArrayList與HashMap, 而少使用Vector與Hashtable。

Ø         在單線程中使用ArrayList與HashMap, 而在多線程中如果需要進行線程同步可以使用Vector與Hashtable, 但也可以用synchronized對ArrayList與HashMap進行同步, 不過同步後的ArrayList與HashMap是比Vector與Hashtable慢的。 不過我認為需要進行線程同步的地方並不多。 如果一個變量定義在方法內部同時隻可能有一個線程對之進行操作, 就不必要進行同步, 如果定義在類的內部並且不是靜態的, 屬於實例變量, 而這個類並冇有被多線程使用也就不必要同步。
一般自己寫的程序很少會自己去另開線程的, 但在Web開發的時候, 如果用了Servlet, 則每個request都是一個線程, 也就是說每個Servlet都是在多線程環境下運行的, 如果Servlet中使用了全局靜態的成員變量就得小心點兒, 如果需要同步就得在方法上加上synchronized修飾符, 如果允許多個線程操作它, 並且你知道不會有什麼衝突問題就可以大膽的使用ArrayList與HashMap。 另外如果在多線程中有線程在對ArrayList或HashMap進行修改(結構上的修改), 而有一個線程在用Iterator進行讀取操作, 這個時候就有可能會拋ConcurrentModificationException, 因為用Iterator的時候, 不允許原List的結構改變。但可以用get方法來取。


常用技巧:

1.         采用麵向接口的編程技巧, 比如現在需要寫一個共通函數,對矢量集合類諸如Vector,ArrayList,HashSet等等進行操作, 但我並不知道最終用戶會具體傳給我什麼類型的類, 這個時候我們可以使用Collection接口, 從而使代碼具有很大的靈活性。 代碼示例如下:

/**

 * 將list裡麵的所有元素用sep連接起來,

 * list可以為Vector, ArrayList, HashSet等。

 */

public static String join(String sep, Collection list) {

   StringBuffer sb = new StringBuffer();

   Iterator iterator = list.iterator();

   while (iterator.hasNext()) {

          sb.append(iterator.next());

          if (iterator.hasNext()) { sb.append(sep); }

   }

   return sb.toString();

}


2.         利用Set進行Unique, 比如有一組對象(其中有對象是重複的), 但我們隻對不同的對象感興趣, 這個時候可以使用HashSet這個集合類, 然後可以通過覆蓋Object的equals方法來選擇自定義判斷相等的rule。 缺省的是地址判斷。 例:

class DataClass {

   private String code = null;

   private String name = null;


   public void setCode(String code) {this.code = code; }

   public String getCode() {return this.code; }

   public void setName(String name) {this.name = name; }

   public String getName() {return this.name; }

   public boolean equals(DataClass otherData) {

          if (otherData != null) {

                 if (this.getCode() != null&& this.getCode().equals(otherData.getCode()) {

                        return true;

                 }

          }

          return false;

   }}

DataClass data1 = new DataClass();

DataClass data2 = new DataClass();

data1.setCode("1");

data2.setCode("1");

HashSet singleSet = new HashSet();

singleSet.add(data1);

singleSet.add(data2);

結果singleSet裡麵隻有data1, 因為data2.equals(data1), 所以data2並冇有加進去。


3.         靈活的設計集合的存儲方式, 以獲得較高效的處理。 集合裡麵可以再嵌套集合, 例:在ArrayList裡麵存放HashMap, HashMap裡麵再嵌套HashMap。