天天看點

「Java基礎」萬字詳解ArrayList和LinkedList

作者:猿學堂

Java集合體系概述

Java集合大緻可以分為List、Set、Map和Queue,其中List代表有序、可重複的集合,Set代表無序、不可重複的集合,而Map則代表具有映射關系的集合。

Java集合就像是一個容器,隻不過容器裡裝的都是對象,在JAVA 5之前,Java集合對丢失容器中對象的資料類型,把所有對象都當做Object類型處理,從容器取出元素後,還面臨着對象向下轉型的問題,Java5以後新增了泛型(關于泛型,會在Java進階中講解,此處不做深究)。Java集合可以記住容器中對象的資料類型。首先,來檢視Java集合體系的全貌。

「Java基礎」萬字詳解ArrayList和LinkedList

ArrayList

List集合代表一個元素有序、有索引、可重複的集合。List允許存放相同的元素,并且每個元素都有對應的索引,可以通過索引通路指定位置的集合元素。結合ArrayList的特點以及前面章節的内容很容易聯想到學習過的數組, 通過檢視ArrayList源碼可以看到ArrayList的底層就是用數組儲存資料以及對資料操作的。

/**
* 存儲ArrayList元素的數組緩沖區。
* ArrayList的容量是此數組緩沖區的長度。任何
* 空的 ArrayList 等價于 elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* 當添加第一個元素時,将擴充到預設容量。
*/
transient Object[] elementData; // non-private to simplify nested class access           

那麼我們就可以先嘗試手動實習自己的ArrayList。在實作ArrayList之前,先來檢視ArrayList繼承關系圖以及主要方法:

「Java基礎」萬字詳解ArrayList和LinkedList

通過繼承關系圖可以看出ArrayList的繼承關系,下面先對各個接口進行解釋:

RandomAccess:随機通路接口,因為ArrayList底層使用數組實作,是以支援在允許範圍内随機通路。

Cloneable:克隆接口,說明ArrayList支援克隆

Serializable:序列化接口,說明ArrayList支援序列化(關于序列化的内容,将會在Java進階中講解)。

List:接口,提供數組的添加、删除、修改、疊代周遊等操作。

AbstractList:AbstractList 提供了 List 接口的骨架實作,大幅度的減少了實作疊代周遊相關操作的代碼

了解完繼承關系以後,接下來熟悉ArrayList的常用API,了解完ArrayList的基本操作以後,可以更友善的了解ArrayList的源碼以及結構。

ArrayList常用API

前面的内容可以知道ArrayList在Java中通常當做容器使用,當做容器使用就需要具備基本的增删改查方法。

構造方法

首先,需要了解ArrayList常用的構造方法:

  • public ArrayList(int initialCapacity) :建立給定容量的ArrayList,initialCapacity的值不能小于0,不能大于Integer能表示的最大值
  • public ArrayList():建立ArrayList對象,預設建立一個空數組。
  • public ArrayList(Collection<? extends E> c):傳入一個集合,以集合中元素為初始元素建立對象

在上述3個構造方法中,前兩個使用頻率較高,當知道ArrayList中儲存對象的個數時,通常使用第一個構造方法,這樣在ArrayList建立對象時已經初始化好數組的長度了,這樣也就避免了擴容的記憶體開銷。

同理,當不确定元素個數時,通常使用第二個構造方法。

如果需要把一個集合中的元素放入ArrayList,就可以使用第三個構造方法。

下面,通過示例來學習這3個構造方法:

package cn.bytecollege;

import java.util.ArrayList;
import java.util.List;
/**
 * 本例将示範ArrayList的構造方法
 * @author MR.W
 *
 */
public class ArrayListDemo {
	public static void main(String[] args) {
		//建立固定容量的集合
		List list1 = new ArrayList(10);
		//建立不固定容量的集合
		List list2 = new ArrayList();
	}
}
           

常用API

方法 描述
add(Object o) 添加資料
add(int index,Object o) 在制定索引處添加元素
size() 擷取元素個數
get(int index) 擷取索引處的元素
isEmpty() 判斷集合是否為空
indexOf(Object o) 判斷某個元素第一次出現的位置
E remove(int index) 移除索引處元素,并傳回該元素
boolean remove(Object o) 移除元素
clear() 清空元素
set(int index ,E e) 修改索引處的元素
iterator() 擷取疊代器
trimToSize() 減少容量至目前元素個數
contains(Object o) 判斷是否包含某個元素
lastIndexOf(Object o) 判斷某個元素最後一次出現的位置
toArray() 将集合轉換為數組
addAll(Collection<? extends E> c) 集合中添加集合
addAll(int index, Collection<? extends E> c) 索引處添加集合
retainAll(Collection c) 求兩個集合的交集
removeAll(Collection<?> c) 移除傳入集合内的元素
subList(int fromIndex, int toIndex) 擷取子集合

下面,通過示例代碼來學習ArrayList的常用方法:

package cn.bytecollege;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class AddDemo {
	public static void main(String[] args) {
		//集合當中添加元素
		List list = new ArrayList();
		list.add("張無忌");
		list.add("趙敏");
		list.add("小昭");
		//将list轉成數組
		Object[] objects = list.toArray();
		System.out.println(Arrays.toString(objects));
	}
}
           
package cn.bytecollege;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        //添加元素
        list.add(10);
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);
        list.add(30);
        //在索引處,添加元素
        list.add(3,100);
        //擷取元素的個數
        int a = list.size();
        System.out.println(a);
        //判斷集合是否為空
        System.out.println(list.isEmpty());
        //判斷某個元素第一次出現的位置
        System.out.println(list.indexOf(30));
        //移除索引處的元素
        System.out.println(list.remove(1));
        list.set(5,60);
        // 疊代器
        Iterator<Integer> it = list.iterator();
        System.out.println(it.next());
        //清空元素
        list.clear();
        System.out.println(list.size());
        list.trimToSize();
    }
}           
package cn.bytecollege;

import java.util.ArrayList;

public class ArrayListDemo2 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(15);
        list.add(20);
        list.add(25);
        list.add(30);
        list.add(15);
        //判斷是否包含某個元素
        System.out.println(list.contains(10));
        //判斷某個元素最後一次出現的位置
        System.out.println(list.lastIndexOf(15));
        //将集合轉換為數組
        ArrayList arr = new ArrayList();
        arr.add(1);
        arr.add(2);
        arr.add(3);
        //集合中添加集合
//        list.addAll(arr);
        //求兩個集合的交集
        list.retainAll(arr);
//        集合處添加集合
        list.addAll(3,arr);
        list.toArray();
        System.out.println(list.toString());
    }
}           

手動實作ArrayList

通過上一小節的學習可以發現ArrayList中主要的方法就是增、删、改、查,接下來根據ArrayList的方法,手動實作自己的ArrayList。

第一步:需要定義一個數組儲存元素,其次需要定義一個變量儲存數組中元素的個數。以及目前數組的長度和預設初始化的長度

//用于儲存元素個數
private int size;
//儲存元素
private Object[] objects;
//儲存數組的目前長度
private int length;
//儲存數組的預設長度
private final int DEFAULT_LEGTH = 10;           

第二步:定義構造方法,構造方法的目的主要是為了初始化數組

public class MyArray {	
	/**
	 * 定義數組,儲存資料
	 */
	private Object[] objects = null;
	/**
	 * 預設數組長度
	 */
	private final int DEFAULT_LENGTH = 10;
	/**
	 * 數組長度
	 */
	private int length;
	/**
	 * 數組元素個數
	 */
	private int size= 0;
	/**
	 * 預設構造函數,建立數組
	 */
	private final int LOAD = 2;
	public MyArray() {
		length = DEFAULT_LENGTH;
		objects = new Object[length];
	}
	/**
	 * 構造函數,根據使用者傳入長度建立數組
	 * @param length
	 */
	public MyArray(int length) {
		this.length = length;
		objects = new Object[length];
	}
}           

第三步:定義add()方法

public class MyArray {	
	/**
	 * 向數組中添加元素
	 * @param o
	 */
	public void add(Object o) {
		//判斷是否需要擴容
		if(size==length) {
			//元素個數等于了數組長度,需要擴容
			length = length*LOAD;
			objects = Arrays.copyOf(objects,length);
		}
		objects[size]=o;
		size++;
	}	
	public void add(int index,Object o) {
		if(index<0||index>size-1) {
			throw new ArrayIndexOutOfBoundsException("通路越界");
		}else {
			//判斷是否需要擴容
			if(size==length) {
				//元素個數等于了數組長度,需要擴容
				length = length*LOAD;
				objects = Arrays.copyOf(objects,length );
			}
			//先将index位置處的元素已近後面元素向右移動
			System.arraycopy(objects, index, objects, index+1, size-index);
			objects[index] = o;
			size++;
		}
	}
}           

在上述代碼中重載了兩個add()方法,第一個方法預設添加到數組元素尾部,從代碼中可以看出添加元素時先判斷元素個數是否等于數組長度,當元素個數等于數組長度時意味着數組已經滿了,此時,需要擴容,我們擷取到數組原長度并乘以2,然後建立新的數組長度為原數組長度的2倍,并将原數組中的元素複制到新數組,最後将新數組的引用儲存在原數組,擴容完畢後将新添加的元素放置在新數組元素末尾,然後元素個數增加一。如果不需要擴容,則直接将元素添加在數組元素末尾,然後元素個數增加一。

在add(int index,Object o)方法中,因為此時涉及到數組的索引,是以先判斷傳入的索引是否越界,如果越界則抛出異常,沒有越界則繼續執行,當添加元素時也需要先判數組是否已經放滿,如果已經放滿則擴容,擴容以後先将原數組的元素全部複制到新數組,複制完成以後,先将索引處元素到最後一個元素依次向後移動,然後将新元素放入索引位置處,最後将元素個數加一,如果不需要擴容,則直接将索引處元素向後移動,然後将新增的元素放入索引位置處。

第二步:定義删除方法

為了保證數組中所有的元素連續,那麼當删除一個元素需要對被删除元素以後的元素全部向前移動。

/**
 * 數組移除操作
 * @param index
 */
public void remove(int index) {
	if(index<0||index>size-1) {
		throw new ArrayIndexOutOfBoundsException("通路越界");
	}else {
		objects[index]= null;
		System.arraycopy(objects, index+1, objects,index , size-index);
		size--;
	}
}           

由于是要根據數組索引删除元素,是以删除之前要先判斷索引是否越界,如果越界則抛出異常。

删除元素時隻需将索引處的元素置為null,然後将索引處後面的元素全部往前移動1位,最後将元素個數減一即可。

第三步:修改元素

/**
  * 更新數組元素
  * @param index
  * @param o
  */
public void update(int index,Object o) {
	if(index<0||index>size-1) {
		throw new ArrayIndexOutOfBoundsException("通路越界");
	}
	objects[index] = o;
}           

修改元素時,一般是修改某個索引處的元素,是以也要判斷傳入索引是否越界。如果索引沒有越界,則将索引處的元素修改為新元素即可。

第四步:檢視元素

/**
  * 查找某個索引處的元素
  * @param index
  */
public Object get(int index) {
	if(index<0||index>size-1) {
		throw new ArrayIndexOutOfBoundsException("通路越界");
	}
	return objects[index];
}           

擷取索引處元素時,也需要先判斷索引是否越界,如果沒有越界則直接從數組中擷取數組元素即可。

9.2.3 ArrayList添加元素過程

在前面的章節中可以知道ArrayList的底層實作是一個數組,在ArrayList中添加元素的過程本質上就是在ArrayList底層數組添加元素的過程。

下面我們通過分析ArrayList源碼來了解這個過程。

public boolean add(E e) {
    //記錄ArrayList的修改次數
    modCount++;
    //調用重載的add()方法
    add(e, elementData, size);
    //從這裡看出不管元素是否添加成功都傳回了true
    return true;
}           

從add()方法中可以看出,add方法内調用了重載的私有add(E e, Object[] elementData, int s)方法,并且傳回了true,在這裡需要注意的是根據此方法的傳回值判斷元素是否添加成功并沒有任何意義,因為add()方法傳回值恒為true。

private void add(E e, Object[] elementData, int s) {
    //判斷元素個數是否和長度相等
    if (s == elementData.length)
        //擴容
        elementData = grow();
    //将元素放置在擴容後數組的已有元素的末尾
    elementData[s] = e;
    //元素個數增加
    size = s + 1;
}           

在這個方法中首先判斷元素的個數是否等于數組長度,也就是說判斷數組是否已經滿了,如果滿了則進行擴容。不管是否擴容,都将新增的元素放在已有元素的後面,然後元素的個數加一。

那麼ArrayList又是如何擴容的呢?繼續檢視grow()方法。

private Object[] grow() {
    return grow(size + 1);
}           

grow()方法比較簡單,隻是調用了私有的重載grow(intminCapacity)方法。

private Object[] grow(int minCapacity) {
    return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
}           

從源代碼可以看出,在這個grow()方法内部使用了數組複制,并且在數組複制前調用了newCapacity()方法。繼續檢視newCapacity()方法。

private int newCapacity(int minCapacity) {
    //擷取數組目前長度
    int oldCapacity = elementData.length;
    //計算新長度,可以看出新長度是原長度的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //判斷新容量和最小容量大小,如果新容量小于等于最小容量
    if (newCapacity - minCapacity <= 0) {
        //如果目前數組是預設容量長度為0的數組
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            //傳回數組初始長度10
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        //如果最小容量小于0則抛出異常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    }
    //如果新容量大于最小容量,判斷新容量是否比數組長度的最大值小
    //如果新容量小于數組長度最大值則傳回新容量
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);
}           

newCapacity()方法即ArrayList計算擴容後數組長度的核心方法,在這個方法中主要做了以下工作:

  1. 擷取數組原長度并根據元長度計算新長度
  2. 判斷新長度是否比原長度小,如果新長度比原長度小,判斷數組是否是初始的空數組,如果是則傳回預設長度10。
  3. 如果新長度大于原長度,判斷新長度是否大于等于數組長度的最大值(Integer.MAX_VALUE-8),如果不大于則傳回新長度。
  4. 如果大于則調用hugeCapacity()方法。

繼續檢視hugeCapacity()方法。

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }
           

hugeCapacity()方法較為簡單,判斷最小容量是否大于數組的最大長度,如果大于則傳回Integer的最大值,否則傳回數組最大值。

ArrayList和Vector

和ArrayList具有相同功能的類是Vector,Vector是Java早期提供的一個集合類,Vector和ArrayList的方法以及底層的實作基本相似,唯一不同的是Vector的方法都是線程安全的,打開Vector源碼可以發現Vector的方法都是用synchronized修飾的(關于synchronized修飾符,會在多線程中講解),是以Vector效率低于ArrayList。除此之外ArrayList和Vector的差別還展現在以下幾個方面:

  1. ArrayList擴容後的長度是原長度的1.5倍,而Vector擴容後的長度是原長度的2倍
  2. ArrayList調用無參構造方法建立對象時,會建立一個空的Object數組,當添加第一個元素時進行擴容,初始容量為10,當Vector調用無參構造建立對象時,則會直接初始化儲存資料的數組,長度為10。

LinkedList

LinkedList同樣實作了List,也就是說LinkedList和ArrayList的方法基本一緻。除此以外,LinkedList還實作了Deque接口。Deque接口則繼承了Queue接口,因為Queue是指隊列這種資料結構,換句話說就是LinkedList不但可以當做List使用,也可以當做隊列使用(FIFO),并且是雙端隊列,根據隊列的規定,隊列隻能從一端進入資料,另一端出資料,但是雙端隊列任意一端都可以進出資料。下面先來檢視LinkedList繼承關系圖:

「Java基礎」萬字詳解ArrayList和LinkedList

手動實作LinkedList

LinkedList底層結構實作和ArrayList底層資料結構實作有着本質上的差別,通過上一小節的内容可以看出ArrayList底層實作主要依賴數組,而LinkedList底層實作則是依賴連結清單。并且LinkedList底層資料結構是雙向連結清單,是以,需要先定義連結清單資料節點。

class Node{
	Node pre;
	Object data;
	Node next;
	public Node(Node pre, E data, Node next) {
		super();
		this.pre = pre;
		this.data = data;
		this.next = next;
	}
}           

第一步:LinkedList的實作是雙向連結清單,是以需要定義首節點和尾結點。并且需要儲存連結清單中元素的個數。此外,還需要提供無參構造方法,在構造方法内初始化一個空連結清單。

public class MyLinkedList{
	/**
	 * 連結清單元素個數
	 */
	private int size;
	/**
	 * 連結清單首節點
	 */
	private Node first;
	/**
	 * 連結清單尾結點
	 */
	private Node last;
	/**
	 * 預設構造建立一個空連結清單
	 */
	public MyLinkedList() {
		first = null;
		last = null;
		size = 0;
	}
}            

第二步:添加元素

/**
  * 連結清單中添加節點,預設添加在尾部
  * @param Object
  */
public void add(Object e) {
    if(first==null||last==null||size==0) {
		//說明連結清單為空連結清單
		//1.建立新節點
		//2.新節點指為first
		//3.新節點指為last
		Node newNode = new Node(null,e,null);
		first = newNode;
		last = newNode;
	}else {
		//1.建立新節點
		Node newNode = new Node(last,e,null);
		//2.将last節點指向新節點
		last.next = newNode;
			//3.将新節點改為last
		last = newNode;
	}
	size++;
}
           

當直接添加元素時,預設添加在連結清單末尾。添加元素時首先判斷連結清單是否為空連結清單,如果為空連結清單,則新增加的節點既是首節點,也是尾結點,并且沒有前置節點也沒有後置節點,是以,新增的節點前置節點和後置節點都為null,當建立好新增的節點後,将首節點和為節點都指向該節點,然後元素個數加一。

當連結清單不為空連結清單時,隻需要将建立的新節點的前置節點指向尾結點,然後将尾結點指向新建立的節點,然後将元素個數加一。

第二步:定義删除元素方法

/**
	 * 删除索引處節點
	 * @param index
	 * @return
	 */
	public boolean remove(int index) {
		if(index<0||index>size-1) {
			throw new IndexOutOfBoundsException("通路越界");
		}
		if(index==0) {
			if(size==1){
                first = null;
                last = null;
            }else{
                Node removeNode = first;
				first = first.next;
				first.pre = null;
				removeNode.next=null;   
            }
          }
		}else if(index==size-1) {
        	if(size==1){
                first = null;
                last = null;
            }else{
                Node removeNode = last;
                last = last.pre;
                last.next = null;
                removeNode.pre = null;
            }
		}else {  	
            //1.找到索引處的節點
            Node indexNode = getNodeByIndex(index);
            //2.找到索引處的後置節點
            Node next = indexNode.next;
            //3.找到索引處的前置節點
            Node pre = indexNode.pre;
            //4.将索引處前置節點的next指向索引處後置節點
            pre.next = next;
            //5.将索引處後置節點的pre指向索引處前置節點
            next.pre = pre;
		}
		size--;
		return true;
	}           

移除元素時,根據元素索引移除,是以要先判斷索引是否越界,索引越界時抛出異常,如果沒有越界。則判斷删除元素的位置:

當删除的是首節點時,首先判斷元素個數是否是1,如果隻有一個元素,則直接将首節點和尾結點置為null即可。

如果有多個元素時,則先擷取首節點,然後擷取首節點的後置節點并将擷取到節點的pre屬性置為null以及将原來首節點的next屬性置為null,并将擷取到的節點置為新的首結點,最後将元素個數減一即可。

當删除的節點是尾結點時,先判斷元素個數是否為1,如果隻有一個元素,則直接将首節點和尾結點置為null即可。

如果有多個元素時,則先擷取尾結點的前置節點,将擷取到的節點的next屬性和原來尾結點的pre屬性置為null,并将擷取到的節點置為新的尾結點。最後将元素個數減一即可。

當删除的節點是中間節點時,首先需要擷取删除索引處節點的前置節點和後置節點,即擷取n-1處的節點和n+1處的節點,然後将n-1處節點的next指向n+1處節點,并将n+1處的節點pre屬性指向n-1處節點。最後将元素個數減一。

第三步:定義查找方法。

/**
  * 根據傳入的索引找到節點
  * @param i
  * @return
  */
private Node<E> getNodeByIndex(int index){
	//判斷索引越界
	if(index<0||index>size) {
		throw new IndexOutOfBoundsException("通路越界");
	}
	if(index==0) {
		return first;
	}else if(index==size-1) {
		return last;
	}else {
		Node<E> current = first;
		for (int i = 0; i < size&¤t!=null; i++) {
			if(i==index) {
				return current;
			}
			current = current.next;
		}
			
	}
	return first;
}
/**
 * 根據索引擷取元素
 * @param index
 * @return
 */
public E get(int index) {
	Node<E> node = getNodeByIndex(index);
	return node.data;
}           

根據索引擷取元素,需要判斷索引是否越界,如果沒有越界則根據傳入索引判斷擷取的是哪個節點的元素。

當索引值為0時,直接傳回首節點中儲存的資料。

當索引的值為size-1時,直接傳回尾結點中儲存的資料。

當索引的值在0到size-1之間時,從首節點開始周遊,當周遊的節點索引等于index時,傳回該節點中儲存的資料。

第四步:定義修改方法

/**
 * 修改索引處的值
 * @param index
 * @param e
 */
public void set(int index,E e) {
	chcekRange(index);
	Node<E> current  = first;
	for (int i = 0; i < size&¤t!=null;i++,current = current.next) {
		if(i==index) {
			current.data = e;
		}
	}
}           

修改元素時,檢查索引是否越界,從首節點開始周遊,直到找到索引處元素并修改值即可

ArrayList和LinkedList的差別

ArrayList和LinkedList雖然都是List接口的子類,但是在底層實作以及效率上存在以下差別

  1. ArrayList和LinkedList都實作了List接口
  2. ArrayList和LinkedList都是非線程安全的,是以在多線程環境下可能會出現出現不同步的情況
  3. ArrayList底層實作是數組,LinkedList底層實作是雙向連結清單
  4. ArrayList因為底層實作是數組,并且支援随機通路是以查找效率高,但是ArrayList在新增元素時會擴容以及複制數組元素,并且删除時也會進行數組複制,是以增删效率低。而LinkedList不支援随機通路,擷取元素時必須從首節點開始從前往後周遊查找,是以查找效率低。但是增加和删除時最多涉及到兩個節點的操作,是以增删效率高。

ArrayList和LinkedList的周遊

  1. ArrayList和LinkedList都支援使用for循環周遊
package cn.bytecollege;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * 本例将示範使用for循環周遊ArrayList和LinkedList
 * @author MR.W
 *
 */
public class ForDemo {
	public static void main(String[] args) {
		
		List<String> arrayList = new ArrayList<>();
		arrayList.add("宋遠橋");
		arrayList.add("張三豐");
		arrayList.add("張翠山");
		
		for (int i = 0; i < arrayList.size(); i++) {
			System.out.println(arrayList.get(i));
		}
		
		List<String> linkedList = new LinkedList<>();
		linkedList.add("白眉鷹王");
		linkedList.add("金毛獅王");
		linkedList.add("青翼蝠王");
		
		for (int i = 0; i < linkedList.size(); i++) {
			System.out.println(arrayList.get(i));
		}
	}
}
           
  1. 使用foreach周遊
package cn.bytecollege;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
 * 本例将示範使用foreach周遊ArrayList和LinkedList
 * @author MR.W
 *
 */
public class ForeachDemo {
public static void main(String[] args) {
		
		List<String> arrayList = new ArrayList<>();
		arrayList.add("宋遠橋");
		arrayList.add("張三豐");
		arrayList.add("張翠山");
		
		for (String s : arrayList) {
			System.out.println(s);
		}
		
		List<String> linkedList = new LinkedList<>();
		linkedList.add("白眉鷹王");
		linkedList.add("金毛獅王");
		linkedList.add("青翼蝠王");
		
		for (String s : linkedList) {
			System.out.println(s);
		}
		
	}
}
           
  1. 因為ArrayList和LinkedList都繼承了Iterable接口,是以ArrayList和LinkedList都可以使用疊代器進行周遊。
package cn.bytecollege;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class IteratorDemo {
	public static void main(String[] args) {
		List<String> arrayList = new ArrayList<>();
		arrayList.add("宋遠橋");
		arrayList.add("張三豐");
		arrayList.add("張翠山");
		
		Iterator<String> it1 = arrayList.iterator();
		while(it1.hasNext()) {
			System.out.println(it1.next());
		}
		
		List<String> linkedList = new LinkedList<>();
		linkedList.add("白眉鷹王");
		linkedList.add("金毛獅王");
		linkedList.add("青翼蝠王");
		
		Iterator<String> it2 = linkedList.iterator();
		while(it2.hasNext()) {
			System.out.println(it2.next());
		}
	}
}
           

除了Iterator以外,List還提供了ListIterator用于周遊List,方法基本和Iterator類似。

  1. Lambda表達式周遊
package cn.bytecollege;

import java.util.ArrayList;
import java.util.List;
/**
 * 使用Lambda周遊
 * @author MR.W
 *
 */
public class LambdaDemo {
	public static void main(String[] args) {
		List<String> arrayList = new ArrayList<>();
		arrayList.add("宋遠橋");
		arrayList.add("張三豐");
		arrayList.add("張翠山");
		
		arrayList.forEach(str->{
			System.out.println(str);
		});
	}
}