標籤:一半 搜尋 區別 迭代 copy vector rem empty 出現
List介面
此介面的使用者可以對列表中每個元素的插入位置進行精確地控制。使用者可以根據元素的整數索引(在列表中的位置)訪問元素,並搜尋列表中的元素。
特點:
元素存取有序
集合中可以有重複元素,通過元素的equals方法來判斷是否為重複元素(實則為判斷地址是否相等)
元素可以為null
是一個帶有索引的集合,可以通過索引精確操作集合中的元素
List介面常用子類:
ArrayList,--------數組
LinkedList,-------雙向鏈表結構
List介面常用方法:
增加元素:add(Object e):從集合末尾處添加元素
add(int index,Object e):向集合指定的索引處添加元素,原油元素依次後移
刪除元素:remove(Object e):將指定元素對象從集合中刪除,傳回值為被刪除的對象
remove(int index,Object e):將元素從指定索引處刪除,傳回值為被刪除對象
替換元素:set(int index,Object e)將指定索引處的元素替換成指定元素,傳回值為替換前的元素
查詢元素:get‘(int index) 擷取索引處的元素並返回該元素
List<String> list = new ArrayList<String>();//1,添加元素。list.add("小紅");list.add("小梅");list.add("小強");//2,插入元素。插入元素前的集合["小紅","小梅","小強"]list.add(1, "老王"); //插入元素後的集合["小紅","老王","小梅","小強"]//3,刪除元素。list.remove(2);// 刪除元素後的集合["小紅","老王","小強"]//4,修改元素。list.set(1, "隔壁老王");// 修改元素後的集合["小紅","隔壁老王","小強"]Iterator<String> it = list.iterator();while (it.hasNext()) { String str = it.next(); System.out.println(str);}
因為List集合有索引,也可以用索引來進行迭代
for (int i = 0; i < list.size(); i++) { String str = list.get(i); System.out.println(str); } Iterator的並發修改異常
public class IteratorDemo {//在list集合迭代元素中,對元素進行判斷,一旦條件滿足就添加一個新元素 public static void main(String[] args) { //建立List集合 List<String> list = new ArrayList<String>(); //給集合中添加元素 list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); //迭代集合,當有元素為"abc2"時,集合加入新元素"a" Iterator<String> it = list.iterator(); while(it.hasNext()){ String str = it.next(); //判斷取出的元素是否是"abc2",是就添加一個新元素 if("abc2".equals(str)){ list.add("a");// 該操作會導致程式出錯 } } //列印容器中的元素 System.out.println(list); }}
運行上述代碼發生了錯誤 java.util.ConcurrentModificationException[L1] 這是什麼原因呢?
在迭代過程中,使用了集合的方法對元素進行操作。導致迭代器並不知道集合中的變化,容易引發資料的不確定性。
並發修改異常解決辦法:在迭代時,不要使用集合的方法操作元素。
並發修改異常
通過ListIterator迭代器操作元素是可以的,ListIterator的出現,解決了使用Iterator迭代過程中可能會發生的錯誤情況。
List集合儲存資料的結構:
資料存放區的常用結構有:堆棧、隊列、數組、鏈表。
堆棧,採用該結構的集合,對元素的存取有如下的特點:
先進後出,
棧的入口、出口的都是棧的頂端位置
壓棧:就是存元素。即,把元素儲存到棧的頂端位置,棧中已有元素依次向棧底方向移動一個位置。
彈棧:就是取元素。即,把棧的頂端位置元素取出,棧中已有元素依次向棧頂方向移動一個位置。
隊列,採用該結構的集合,對元素的存取有如下的特點:
先進先出
隊列的入口、出口各佔一側
數組
尋找元素快:通過索引,可以快速存取指定位置的元素
指定索引位置增加元素:需要建立一個新數組,將指定新元素儲存在指定索引位置,再把原數組元素根據索引,複製到新數組對應索引的位置。
指定索引位置刪除元素:需要建立一個新數組,把原數組元素根據索引,複製到新數組對應索引的位置,原數組中指定索引位置元素不複製到新數組中
鏈表
多個節點之間,通過地址進行串連。例如,多個人手拉手,每個人使用自己的右手拉住下個人的左手,依次類推,這樣多個人就連在一起了。
尋找元素慢:想尋找某個元素,需要通過串連的節點,依次向後尋找指定元素
增刪元素快:
增加元素:操作如左圖,只需要修改串連下個元素的地址即可。
刪除元素:操作如右圖,只需要修改串連下個元素的地址即可。
ArrayList集合
ArrayList集合資料存放區的結構是數組結構。元素增刪慢,尋找快,由於日常開發中使用最多的功能為查詢資料、遍曆資料,所以ArrayList是最常用的集合。
LenkedList集合
LinkedList集合資料存放區的結構是鏈表結構。方便元素添加、刪除的集合。實際開發中對一個集合元素的添加與刪除經常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。
LinkedList是List的子類,List中的方法LinkedList都是可以使用
LinkedList<String> link = new LinkedList<String>(); //添加元素 link.addFirst("abc1"); link.addFirst("abc2"); link.addFirst("abc3"); //擷取元素 System.out.println(link.getFirst()); System.out.println(link.getLast()); //刪除元素 System.out.println(link.removeFirst()); System.out.println(link.removeLast()); while(!link.isEmpty()){ //判斷集合是否為空白 System.out.println(link.pop()); //彈出集合中的棧頂元素 }
Vector集合資料存放區的結構是數組結構,為JDK中最早提供的集合。Vector中提供了一個獨特的取出方式,就是枚舉Enumeration,它其實就是早期的迭代器。Vector集合已被ArrayList替代。枚舉Enumeration已被迭代器Iterator替代。
List和Array的區別:
相同之處:
都可以表示一組同類型的對象
都使用下標進行索引
不同之處:
數組可以儲存任何類型元素
List不可以儲存基礎資料型別 (Elementary Data Type),需要封裝
數組容量固定,List可以動態增長
數組效率高; List 由於要維護額外內容,效率相對低一些
總結:
容量固定時 優先使用數組,容納類型更多,更高效
在容量不確定的情況下List更有優勢
ArrayList 的擴容機制:
public boolean add(E object) { Object[] a = array; int s = size; //當放滿時,擴容 if (s == a.length) { //MIN_CAPACITY_INCREMENT 為常量,12 Object[] newArray = new Object[s + (s < (MIN_CAPACITY_INCREMENT / 2) ? MIN_CAPACITY_INCREMENT : s >> 1)]; System.arraycopy(a, 0, newArray, 0, s); array = a = newArray; } a[s] = object; size = s + 1; modCount++; return true;}
- 當 ArrayList 的元素個數小於 6 時,容量達到最大時,元素容量會擴增 12;
- 反之,增加 當前元素個數的一半。
LinkedList 的擴容機制:
public boolean add(E object) { return addLastImpl(object);}private boolean addLastImpl(E object) { Link<E> oldLast = voidLink.previous; Link<E> newLink = new Link<E>(object, oldLast, voidLink); voidLink.previous = newLink; oldLast.next = newLink; size++; modCount++; return true;}
可以看到 linkedList沒有擴容機制!
這是由於 LinedList 實際上是一個雙向鏈表,不存在元素個數限制,使勁加就行了。
transient Link<E> voidLink;private static final class Link<ET> { ET data; Link<ET> previous, next; Link(ET o, Link<ET> p, Link<ET> n) { data = o; previous = p; next = n; }}在 List 中有兩個轉換成 數組 的方法:
Object[] toArray()
返回一個包含 List 中所有元素的數組;
T[] toArray(T[] array)
作用同上,不同的是當 參數 array 的長度比 List 的元素大時,會使用參數 array 儲存 List 中的元素;否則會建立一個新的 數組存放 List 中的所有元素;
JAVA-基礎-List介面