容器的種類
爲什麼要使用容器? 因爲數組不能夠滿足日常的開發需求,數組有以下弊端:
- 長度難以擴充
- 數據的類型必須相同
- 數組無法獲得有多少個真實的數據,只能獲得數組的長度。
在Java中有常用的三種類型的容器,分別是List 、Map、Set,基於這個三個基本的類型,派生出很多其它的類型,具體關係如下:
三者的區別:
- Set(集):與list都是有Collection類的派生出來, 分辨各個元素的標識是HashCode,所以元素不能有重複
- List(列表):是一個有序的列表,元素如果有重複,也會一一列出來。
- Map(映射): Map是我們常說的鍵值對,有key和Value兩個元素
使用方法:
@Test public void ContainerTest() { String string[] = {"i", "am", "am", "xiao", "ming"}; List<String> list = new ArrayList<String>(); for (String s : string) { list.add(s); } System.out.println("List執行結果:"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // Set<String> set = new HashSet<String>(); for (String s : string) { set.add(s); } Iterator iterator = set.iterator(); System.out.println("==================="); System.out.println("Set 執行結果:"); while (iterator.hasNext()) { System.out.println(iterator.next()); } }
運行結果:
List執行結果: i am am xiao ming =================== Set 執行結果: ming xiao i am
三者的區別可以表示如下圖:
各個容器的說明和使用
List
ArrayList
ArrayList是List一個派生類,非線安全,是基於Object數組實現的可動態擴展的容器,在調用Add的時候會判斷當前的長度是否已經超過了Size.對應的Add方法:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
LinkList
LinkList與ArrayList區別是LinkList 是基於鏈表的結構設計 ,插入和刪除的性能要高於ArrayList,查詢的效率低於LinkList,使用方法基本一致,也是非線安全,下面看下性能測試代碼:
@Test public void ListAdd() { System.out.println("ArrayList ADD耗時:" + AddList(new ArrayList())); System.out.println("LinkedList ADD耗時:" + AddList(new LinkedList())); //測試Edit final int N = 50000; Integer vals[] = new Integer[N]; Random r = new Random(); for (int i = 0, currval = 0; i < N; i++) { currval += r.nextInt(100) + 1; vals[i] = new Integer(currval); } List lst = Arrays.asList(vals); System.out.println("ArrayList Search耗時:" + SearchList(new ArrayList(lst))); System.out.println("LinkedList Search耗時:" + SearchList(new LinkedList(lst))); } long AddList(List list) { final int N = 50000; long start = System.currentTimeMillis(); Object o = new Object(); for (int i = 0; i < N; i++) list.add(0, o); return System.currentTimeMillis() - start; } long SearchList(List lst) { final int N = 50000; long start = System.currentTimeMillis(); for (int i = 0; i < N; i++) { int index = Collections.binarySearch(lst, lst.get(i)); if (index != i) System.out.println("***錯誤***"); } return System.currentTimeMillis() - start; }
運行結果:
ArrayList ADD耗時:396 LinkedList ADD耗時:9 ArrayList Search耗時:20 LinkedList Search耗時:8330
Vector
比arraylist多了個同步化機制(線程安全),用法相同,但效率比較低,不建議使用。
Map
HashMap 和 HashTable
二者在使用上功能差不多,區別是HashMap是線程不安全,允許多線程去同時訪問,允許插入空值。 而HashTable是相反的,對於HapMap的使用,可以參考下面代碼:
Map map=new HashMap(); map.put("key","abc"); map.put("key1","abc1"); map.put("key2","abc2"); System.out.println(map.get("key")); map.remove("key"); System.out.println(map.values()); System.out.println(map.keySet()); System.out.println(map.entrySet());
運行結果如下:
abc [abc1, abc2] [key1, key2] [key1=abc1, key2=abc2]
TreeMap
是一個有順序的HaspMap
手工實現容器ArrayList
根據上面的分析,我們可以手工實現一個ArrayList 代碼如下:
public class MyArrayList { private Object[] _arr; private int _size; public MyArrayList() { _arr = new Object[10]; this._size = 0; } public void Add(Object obj) { if (this._size >= this._arr.length) { Object[] newArray = new Object[2 * this._size + 1]; for (int i = 0; i < this._size; i++) { newArray[i] = this._arr[i]; } this._arr = newArray; this._arr[this._size] = obj; this._size++; } else { this._arr[this._size] = obj; this._size++; } } public int Size() { return this._size; } public Object get(int index) { if (index > this._size) { throw new IndexOutOfBoundsException("索引超出界限"); } return this._arr[index]; } }
使用方法:
@Test public void PrintMyArr(){ MyArrayList list=new MyArrayList(); for (int i=0;i<10000;i++){ list.Add(i); } System.out.println(list.Size()); System.out.println(list.get(503)); System.out.println(list); }
(本文完)
作者:老付 如果覺得對您有幫助,可以下方的訂閱,或者選擇右側捐贈作者,如果有問題,請在捐贈後諮詢,謝謝合作 如有任何知識產權、版權問題或理論錯誤,還請指正。 自由轉載-非商用-非衍生-保持署名,請遵循:創意共享3.0許可證 交流請加羣113249828:點擊加羣 或發我郵件 [email protected]