JavaEE - 11集合Collection-List
阿新 • • 發佈:2020-12-07
Javaee - 11集合Collection-List
(4)Collection子介面:List介面
(4.1)List介面概述
- 鑑於陣列儲存資料的侷限性,通常使用List替代陣列。List-> "動態"陣列。
- List集合類中元素有序、可重複,集合中的每個元素都有其對應的順序索引。
- List容器中的元素都對應一個整數型的序號記載其在容器中的位置,可以根據序號存取容器中的元素。
- JDK API中List介面的實現類有: ArrayList、 LinkedList和 Vector。三者異同。
- ArrayList: List介面的主要實現類;執行緒不安全,效率高;底層使用Object[]elementData儲存
- LinkedList:對於頻繁插入刪除操作,效率比ArrayList高;底層使用雙向列表儲存
- Vector: List介面的古老實現類;執行緒安全,效率低;底層使用Object[] elementData儲存
(4.2)ArrayList
(4.2.1)JDK 7下原始碼分析
- ArrayList list = new ArrayList(); //底層建立初始長度為10的Object[]陣列elementData
- list.add(123); // elementData[0] = new Integer(123);
- ......
- list.add(11); //如果此次新增導致底層elementData陣列容量不夠,則擴容
- 建議:開發中使用帶引數的構造器: ArrayList list = new ArrayList(int capacity); 節省擴容的效能開支
(4.2.2)JDK 8中的變化
- ArrayList list = new ArrayList(); //底層Object[]陣列elementData初始化為{},不建立長度10的陣列
- list.add(123); //第一次呼叫add時,底層建立長度10的陣列,新增元素elementData[0] = new Integer(123);
- 後續的新增和擴容操作與JDK7一樣。
- JDK7物件的建立類似於單例的餓漢式,JDK8的ArrayList物件建立類似於單例的懶漢式,延遲了陣列建立,節省記憶體。
(4.2.3)重要原始碼(JDK8)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { // 不帶引數,初始化為空陣列 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
private static final Object[] EMPTY_ELEMENTDATA = {}; // 帶引數初始化 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; if (minCapacity > minExpand) { 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) // MAX_ARRAY_SIZE = Integer.MAX_VALUE -8 newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
(4.3)LinkedList
- linkedList 是一個雙向連結串列,內部沒有宣告陣列,而是定義了Node型別的first和last,用於記錄首末元素。
- 定義內部類Node,作為LinkedList中儲存資料的基本結構。
- Node除了儲存資料,還定義了兩個變數:prev變數記錄前一個元素的位置,next變數記錄下一個元素的位置。
- 沒有初始化大小,也沒有擴容的機制,就是一直在前面或者後面新增Node。
對於雙向連結串列Node的理解
private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
在列表尾部插入一個元素
- 先將列表最後一個元素last儲存為Node節點 l;
- 組裝一個新的Node節點newNode, Node的prev是l,值為e, next為null。
- 將新的節點newNode作為列表的最後一個元素。
- 將原來元素的next指向 newNode新節點。如果是第一個元素,則把first也指向新節點。
- 列表size加1,modCount加1。
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; } void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
(4.4)Vector
JDK7和 JDK8中通過Vector()構造器建立物件時,底層都建立了長度為10的陣列。在擴容方面,預設擴容為原來的陣列長度的2倍。
public Vector() { this(10); } public synchronized void ensureCapacity(int minCapacity) { if (minCapacity > 0) { modCount++; ensureCapacityHelper(minCapacity); } } private void ensureCapacityHelper(int minCapacity) { // 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 + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
(4.5)List介面
除了繼承Collection的方法,List添加了一些根據索引來操作集合元素的方法。
- void add(int index, Object ele): 在index位置插入ele元素
- boolean addAll(int index, Collection eles):從index位置開始將eles中的所有元素新增進去。
- Object get(int index): 獲取指定index位置的元素
- int indexOf(Object obj): 返回obj在集合中首次出現的位置
- int lastIndexOf(Object obj): 返回obj在當前集合中末次出現的位置
- Object remove(int index): 移除指定index位置的元素,並返回此元素
- Object set(int index, Object ele): 設定指定index位置的元素為ele
- List subList(int fromIndex, int toIndex): 返回從fromIndex到toIndex位置的子集合。
@Test public void test1(){ ArrayList list = new ArrayList(); list.add(123); list.add("acd"); list.add(new Person("Tom",12)); System.out.println(list); //[123, acd, Person@27dd1a] list.add(2,"dddd"); System.out.println(list); //[123, acd, dddd, Person@27dd1a] System.out.println(list.get(2)); //dddd System.out.println(list.set(2,"DDDD")); //dddd System.out.println(list); //[123, acd, DDDD, Person@27dd1a] }
區分List中的remove(int index)和remove(Object obj) // remove(2) remove(new Integer(2))
@Test public void testListRemove(){ List list = new ArrayList(); list.add(1); list.add(2); list.add(3); updateList(list); System.out.println(list); //[1,2] } private static void updateList(List list){ list.remove(2); // index位置 }
@Test public void testListRemove(){ List list = new ArrayList(); list.add(1); list.add(2); list.add(3); updateList(list); System.out.println(list); // [1,3] } private static void updateList(List list){ list.remove(new Integer(2)); // 刪除元素為2 }
3.HashMap
HashMap 初始化大小是 16 ,擴容因子預設0.75(可以指定初始化大小,和擴容因子)
擴容機制.(當前大小 和 當前容量 的比例超過了 擴容因子,就會擴容,擴容後大小為 一倍。例如:初始大小為 16 ,擴容因子 0.75 ,當容量為12的時候,比例已經是0.75 。觸發擴容,擴容後的大小為 32.)