Android中的容器

List

java.util包提供了兩種java

ArrayList
LinkedList

ArrayList比LinkedList經常使用不少,緣由是:
ArrayList查找更容易算法

ArrayList

ArrayList封裝了一個數組Object[]數組

  • 數組的初始化緩存

    ArrayList array = new ArrayList();

    封裝一個空數組, {}安全

    ArrayList array = new ArrayList(10);

    封裝一個大小爲10的數組 new Object[10];
    性能優化

  • 數組如何實現擴容
    數據結構

    ArrayList.add/addAll都須要先進行擴容檢查,
    相似,併發

    對象調用方法,要進行對象判空,
     UI操做以前要進行,線程檢查

    擴容檢查: size+增長的大小 與 數組.length 比較
    計算數組擴容的數組長度:性能

  首先,擴容至原數組大小的一倍,size+增長的大 小與其比較:
       若是大於,擴容至原數組大小的一倍
       若是小於,擴容至size+增長的大小;優化

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);
   }

擴容使用的是: Array.copyof(array, newLen)

  • removeAll如何實現

    與remove()不一樣,remove使用System.copy完成數組的 部分移動

    而removeAll,使用的算法:

    ArrayList array1 = new ArrayList();
    array1.addAll({0,3,5,7,3,6});
    int[] array2 = {3,5,4};
    array1.removeAll(array2);

    首先,遍歷array1中每一個元素,若元素 不在array2內,將計數位置的值設置爲元素的值並將計 數+1;

    遍歷完成後,計數爲數組剩餘元素的個 數,將計數以後的元素清空.

    算法詳細:

    &#8194;&#8194;0,3,5,7,3,6 ;<br>
       &#8194;&#8194;遍歷以後,計數爲2,數組爲0,7,6,7,3,6;<br>
       &#8194;&#8194;清空以後,0,7,6,null,null,null;
  • trimToSize()

    數組擴容後即便刪除元素,數組的length也不會該改變,

    意味着即便刪除了某些元素數組佔用的內存大小不會改變;

    數組只會不斷的增大,且出現大量null的元素.

    trimToSize()方法用於改變數組的length,將爲null的元素釋放掉,等待GC

    這也是防止內存浪費的一種方式,當ArrayList經歷了屢次刪除操做以後,使用trimToSize(),避免內存浪費.

    trimToSize()使用Array.copyof()來改變數組的length
  • 總結

    ArrayList本質上維護了一個數組,也就意味者它具備數組的優缺點:增刪難,查找易

LinkedList

  • Node的數據結構

    Node<E> {
        E element;
        Node<E> prev;
        Node<E> next;
    }
  • 基本結構

    Node<E> first, last

    Linked是雙向鏈表,first,last指向表頭,表尾

  • 總結

    LinkedList是一個Deque,雙向鏈表,

    增刪易,查找難,形成在編碼中不多使用

Map

java.util包提供了兩種Map:

1.HashMap

2.TreeMap

Android爲了性能優化,提供了HashMap的替代品:

1.ArrayMap

2.SparseMap

它倆能夠在數據量都在千級之內的狀況下,

  若是key的類型爲int,使用SparseMap,

  若是key的類型爲其它類型,使用ArrayMap

HashMap相比TreeMap更經常使用

HashMap

  • 數據結構

    Node的數據結構:

    Node<K,V> {
        int hash;
        K key;
        V value;
        Node<K,V> next;
    }

    基本數據結構:

    Node<K,V>[] table;
    float loadFoctor;//默認值0.75f
    int threshold;

    能夠看出HashMap的數據結構是數組+鏈表

  • 擴容

    1. 何時擴容

      當調用put/putAll時,實際上都是調用putVal方法

        先建立Node,再查看新的Node放入數組,仍是鏈表;

        當++size>threshold,則須要擴容

    2. table如何擴容

      它的擴容包含兩個步驟:

      1. 肯定擴容的大小;
      2. 如何移動元素,包含數組中的元素與鏈表中的元素;<br>

  肯定擴容的大小:

    threshold默認值 = 16*0.75f=12

     每次擴容,

    先建立一個threadhold大小的數組,賦給tble,也就是擴容至threadhold

    再,threadhold = threadhold <<1,擴大一倍



  如何移動元素,包含數組中的元素與鏈表中的元素:

    1.若是元素只在數組裏,而沒有鏈表:

      新的位置是 e.hash&(newCap-1)

    2.元素在鏈表上:

      根據(e.hash & oldCap) == 0 決定是在原位置仍是在原位置+oldCap上

      鏈表可能會分爲兩部分

TreeMap

  • 數據結構

    TreeMapEntry的數據結構

    TreeMapEntry<K, V> {
        K key;
        V value;
        TreeMapEntry<K, V> left;
        TreeMapEntry<K, V> right;
        TreeMapEntry<K, V> parent;
    }

    TreeMap的數據結構:

    TreeMapEntry<K, V> root;
    Comparator<? super K> comparator;
  • TreeMap其實是紅黑二叉樹

SparseArray

  • 數據結構

    int[] mKeys;
    Object[] mValues;
  • 總結

    官方推薦去使用SparseArray<E>去替換HashMap<Integer,E>,
    犧牲了部分效率換來內存

ArrayMap

LinkedHashMap

  • 能夠看做HashMap+LinkedList,用於保證插入順序
  • 通常用於做爲緩存

Java中的線程安全的容器

同步容器

Vector

HashTable

併發容器

用於讀寫分離,實現讀併發,寫同步

併發的不一樣策略:

  1.Blocking容器

  2.CopyOnWrite容器

  3.Concurrent容器

Blocking容器

  • 併發策略:

  用於解決限制容量的容器的存取問題

  相似生產者-消費者

  容器爲空時,阻塞取線程

  容器滿時,阻塞存線程

CopyOnWrite容器

  • 併發策略:

  寫時賦值,即添加元素時,先複製整個容器,添加到複製的容器中,
  再將容器引用指向複製的容器,達到讀的最大併發;
   適用於讀多寫少的狀況;

Concurrent容器

  • 併發策略:

  使用分段鎖,首先將容器分紅多段,每段使用不一樣的鎖,對不一樣段達到讀寫併發,相同段讀併發,寫同步

相關文章
相關標籤/搜索