Java中的容器

容器的種類

爲什麼要使用容器? 因爲數組不能夠滿足日常的開發需求,數組有以下弊端:

  1. 長度難以擴充
  2. 數據的類型必須相同
  3. 數組無法獲得有多少個真實的數據,只能獲得數組的長度。

在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]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章