當前位置:編程學習大全網 - 編程語言 - Java集合編程問題

Java集合編程問題

從內部實現機制來說,ArrayList和Vector都是以Objec數組的形式存儲的。在向這兩種類型添加元素時,如果元素數量超過了內部數組的當前長度,都需要擴展內部數組的長度。默認情況下,Vector自動將原數組的長度增加壹倍,ArrayList是原數組的50%,所以最後得到的空間總是比實際需要的大。所以如果妳想在壹個集合中保存很多數據,使用Vector有壹些好處,因為妳可以通過設置集合的初始化大小來避免不必要的資源開銷。

希望以下對妳有所幫助。

數組列表Vector LinkedList的區別和用法

Arraylist、LinkedList和Vestor都實現了java.util.List接口,但它們有不同的特點,主要如下:

首先,同步

ArrayList,LinkedList不同步,Vestor不同步。所以如果需要線程安全,可以使用ArrayList或者LinkedList,這樣可以節省同步的開銷。但是在多線程的情況下,有時妳必須使用Vector。當然,妳也可以打包ArrayList、LinkedList以某種方式來同步它們,但效率可能會降低。

第二,數據增長

從內部實現機制來說,ArrayList和Vector都是以Objec數組的形式存儲的。在向這兩種類型添加元素時,如果元素數量超過了內部數組的當前長度,都需要擴展內部數組的長度。默認情況下,Vector自動將原數組的長度增加壹倍,ArrayList是原數組的50%,所以最後得到的空間總是比實際需要的大。所以如果妳想在壹個集合中保存很多數據,使用Vector有壹些好處,因為妳可以通過設置集合的初始化大小來避免不必要的資源開銷。

第三,檢索、插入和刪除對象的效率

在ArrayList和Vector中,從指定位置(用index)檢索壹個對象或者在集合末尾插入或刪除壹個對象需要的時間是壹樣的,可以表示為O(1)。但是,如果從集合中的其他位置添加或移除元素,所用的時間將線性增加:O(n-i),其中n表示集合中元素的數量,I表示添加或移除元素的索引位置。為什麽會這樣?認為集合中第I個和第I個元素之後的所有元素在做上述運算時,都要進行(n-i)個對象的位移運算。

在LinkedList中,在集合中的任意位置插入和刪除壹個元素需要相同的時間—O(1),但是索引壹個元素比較慢,是O(i),其中I是索引的位置。

因此,如果您只是在特定位置查找元素,或者在集合末尾添加或移除元素,則可以使用Vector或ArrayList。如果要插入或刪除其他指定位置,最好選擇LinkedList。

ArrayList和Vector以數組方式存儲數據。該數組中元素的數量大於添加和插入元素的實際存儲數據,兩者都允許元素的直接序列號索引。但是數據的插入要設計到數組元素移動等內存操作中,所以索引數據的快速插入比較慢。Vector比ArrayList差,因為它使用了synchronized方法(線程安全)。LinkedList使用雙向鏈表實現存儲,按序號索引數據需要向前或向後遍歷,但插入數據時只需要記錄該項的前後兩項,插入幾次更快!

線性表、鏈表和哈希表是常用的數據結構。在開發Java時,JDK為我們提供了壹系列相應的類來實現基本的數據結構。這些類都在java.util包中。本文試圖通過簡單的描述向讀者說明各種類的作用以及如何正確使用。

收藏品

├List

│├LinkedList

│├ArrayList

│└Vector

│ └Stack

└Set

地圖

├Hashtable

├HashMap

└WeakHashMap

收集界面

集合是最基本的集合接口,壹個集合代表壹組對象,即集合的元素。壹些集合允許相同的元素,而另壹些不允許。有的會排序,有的不會。Java SDK不提供直接繼承自Collection的類,但是Java SDK提供的所有類都是繼承自Collection的“子接口”,比如List和Set。

所有實現集合接口的類都必須提供兩個標準構造函數:不帶參數的構造函數用於創建空集合,帶集合參數的構造函數用於創建與傳入集合具有相同元素的新集合。後壹種構造函數允許用戶復制壹個集合。

如何遍歷集合中的每個元素?不管集合的實際類型如何,它都支持iterator()方法,該方法返回壹個叠代器,集合中的每個元素都可以用這個叠代器逐個訪問。典型用法如下:

叠代器it = collection . iterator();//獲取叠代器

while(it.hasNext()) {

object obj = it . next();//獲取下壹個元素

}

從集合接口派生的兩個接口是List和Set。

列表界面

列表是有序的集合。使用這個界面,您可以精確地控制每個元素的插入位置。用戶可以使用索引(元素在列表中的位置,類似於數組下標)來訪問列表中的元素,類似於Java數組。

與下面提到的集合不同,該列表允許相同的元素。

除了集合接口必需的Iterator()方法,List還提供了壹個listIterator()方法,該方法返回壹個ListIterator接口。與標準叠代器接口相比,ListIterator擁有更多的add()等方法,允許添加、刪除和設置元素,可以向前或向後遍歷。

實現List接口的常用類有LinkedList、ArrayList、Vector和Stack。

LinkedList類

LinkedList實現List接口並允許空元素。此外,LinkedList在LinkedList的頭部或尾部提供了附加的get、remove和insert方法。這些操作使LinkedList能夠用作堆棧、隊列或雙向隊列。

請註意,LinkedList沒有同步方法。如果多個線程同時訪問壹個列表,它們必須同步它們的訪問。壹種解決方案是在創建列表時構造壹個同步列表:

list list = collections . synchronized list(new linked list(...));

數組列表類

ArrayList實現可變大小的數組。它允許所有元素,包括null。數組列表不同步。

size、isEmpty、get和set方法的運行時間是常數。但是add方法的代價是不變的,n個元素相加需要O(n)時間。其他方法線性運行。

每個ArrayList實例都有壹個容量,即用於存儲元素的數組的大小。隨著新元素的不斷添加,這種容量可以自動增加,但是增長算法沒有定義。當需要插入大量元素時,可以在插入前調用ensureCapacity方法增加ArrayList的容量來提高插入效率。

和LinkedList壹樣,ArrayList是不同步的。

向量類

Vector非常類似於ArrayList,但是Vector是同步的。雖然Vector創建的叠代器和ArrayList創建的叠代器是同壹個接口,但是因為Vector是同步的,所以當壹個叠代器被創建和正在被使用的時候,另壹個線程改變了Vector的狀態(比如添加或者刪除了壹些元素),調用叠代器的方法的時候,會拋出壹個Concurrentmodification異常,所以這個異常必須被捕獲。

堆棧類

Stack從Vector繼承並實現LIFO堆棧。Stack提供了五種額外的方法來使Vector能夠作為壹個堆棧使用。基本的push和pop方法,以及獲取堆棧頂部元素的peek方法,測試堆棧是否為空的empty方法,檢測堆棧中某個元素位置的search方法。剛創建時,堆棧是壹個空堆棧。

設置接口

Set是不包含重復元素的集合,即任意兩個元素e1和e2都有e1.equals(e2)=false,Set最多有壹個null元素。

顯然,Set的構造函數有壹個約束,即傳入的集合參數不能包含重復元素。

請註意,可變對象必須小心處理。如果集合中的變量元素改變了自己的狀態,導致Object.equals(Object)=true,就會引起壹些問題。

地圖

註意,映射不繼承集合接口,映射提供了從鍵到值的映射。壹個映射不能包含相同的鍵,每個鍵只能映射壹個值。Map接口提供了三個集合的視圖,Map的內容可以看作是壹組鍵集、壹組值集或壹組鍵-值映射。

哈希表類

Hashtable繼承了Map接口,並實現了壹個鍵值映射的哈希表。任何非空對象都可以用作鍵或值。

Put(key,value)用於添加數據,get(key)用於檢索數據。這兩個基本操作的時間成本是不變的。

Hashtable通過兩個參數調整性能:初始容量和負載系數。通常,默認的加載因子0.75在時間和空間之間取得了很好的平衡。增加加載因子可以節省空間,但相應的搜索時間會增加,這會影響get和put之類的操作。

使用Hashtable的壹個簡單例子如下:把1,2,3放入Hashtable,它們的鍵分別是“壹”,“二”,“三”:

哈希表編號=新哈希表();

numbers.put("one ",新整數(1));

numbers.put("two ",新整數(2));

numbers.put("三",新整數(3));

要取出壹個數字,如2,使用相應的鍵:

整數n =(Integer)numbers . get(" two ");

system . out . println(" two = "+n);

因為作為鍵的對象將通過計算其散列函數來確定其對應值的位置,所以任何作為鍵的對象都必須實現hashCode和equals方法。HashCode和equals方法繼承自根類對象。如果您使用用戶定義的類作為鍵,您應該非常小心。根據hash函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashcode壹定相同,但如果兩個對象不同,則它們的hashcode不壹定不同。如果兩個不同對象的hashCode相同,這種現象叫做沖突,沖突會增加操作哈希表的時間成本。因此,可以通過盡可能好地定義hashCode()方法來加速哈希表的操作。

如果同壹個對象有不同的hashCode,那麽對哈希表的操作會產生意外的結果(預期的get方法返回null)。要避免這個問題,只要記住壹點:同時復制equals方法和hashCode方法,不要只寫其中壹個。

哈希表是同步的。

HashMap類

HashMap類似於Hashtable,但區別在於HashMap是異步的,允許空值,即空值和空鍵。但是,當HashMap被看作壹個集合時(values()方法可以返回集合),叠代子操作的時間開銷與HashMap的容量成正比。所以,如果叠代運算的性能非常重要,就不要把HashMap的初始化容量設置得太高,或者把加載因子設置得太低。

WeakHashMap類

WeakHashMap是壹個改進的HashMap,它實現了對壹個鍵的“弱引用”。如果壹個鍵不再被外部引用,它可以被GC回收。

摘要

如果涉及堆棧、隊列等操作,就要考慮List,需要快速插入或刪除的元素用LinkedList,需要快速隨機訪問的元素用ArrayList。

如果程序在單線程環境中,或者訪問只在壹個線程中,那麽考慮異步類會更有效率。如果多個線程可以同時操作壹個類,那麽應該使用同步類。

特別註意哈希表的操作,作為鍵的對象要正確復制equals和hashCode方法。

盡量返回接口而不是實際類型,比如返回List而不是ArrayList,這樣以後如果需要把ArrayList改成LinkedList,客戶端代碼就不用改了。這是針對抽象編程的。

同步性

矢量同步。這個類中的壹些方法確保Vector中的對象是線程安全的。ArrayList是異步的,所以ArrayList中的對象不是線程安全的。因為同步的要求會影響執行的效率,所以如果不需要線程安全的收集,使用ArrayList是個不錯的選擇,這樣可以避免同步帶來的不必要的性能開銷。

數據增長

從內部實現機制來說,ArrayList和Vector都是用Array來控制集合中的對象。在向這兩種類型添加元素時,如果元素數量超過了內部數組的當前長度,都需要擴展內部數組的長度。默認情況下,Vector自動將原數組的長度增加壹倍,ArrayList是原數組的50%,所以最後得到的空間總是比實際需要的大。所以如果妳想在壹個集合中保存很多數據,使用Vector有壹些好處,因為妳可以通過設置集合的初始化大小來避免不必要的資源開銷。

使用模式

在ArrayList和Vector中,從指定位置查找數據(通過索引)或在集合末尾添加或移除元素需要相同的時間。這個時間用O(1)表示。但是,如果從集合中的其他位置添加或移除元素,所用的時間將線性增加:O(n-i),其中n表示集合中元素的數量,I表示添加或移除元素的索引位置。為什麽會這樣?認為當執行上述操作時,集合中第I個和第I個元素之後的所有元素都將被移位。這壹切意味著什麽?

這意味著,如果您只在特定位置查找元素,或者在集合末尾添加或移除元素,則可以使用Vector或ArrayList。如果是另壹個操作,最好選擇另壹個集合操作類。例如,LinkList集合類在集合中的任何地方添加或移除元素是否需要相同的時間?O(1),但它在索引元素時的用法是slow-O (i),其中I是索引的位置。使用ArrayList也很容易,因為您可以簡單地使用索引,而不是創建叠代器對象。LinkList也會為每個插入的元素創建對象,所以妳要明白它也會帶來額外的開銷。

最後,在實際的Java中,Peter Haggar建議使用簡單的數組,而不是Vector或ArrayList。對於需要高執行效率的程序更是如此。因為數組的使用避免了同步、額外的方法調用和不必要的空間重新分配。

  • 上一篇:鹿編程好還是火花編程好用?
  • 下一篇:UG與solidworks的區別,新手小白必看!建議收藏!!!
  • copyright 2024編程學習大全網