集合初識和用法——List(java)

List是一種有序、提供角標、一維數據列表、允許重複元素、允許null元素的集合。它是collection的一個子接口,其已知實現的子類且常用的有ArrayList、LinkedList和Vector。下面將對List的一些方法的使用和它的常用子類的方法的使用進行介紹。

List的方法測試和使用示例以及說明

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Main {
	public static void main(String[] args) {
	//list也是一個接口,不能創建對象,只能創建其子類對象
		List<Integer> list=new ArrayList<Integer>();
		for(int i=0;i<10;i++){
	//這裏調用的是list自己的add(int index, E element)方法,
	//也可以直接添加元素調用add(E e)方法,這是從collection接口繼承來的方法
   //而這裏用到了list提供角標的特性,在指定位置添加元素
			list.add(i,i);
		}
		System.out.println(list);
   //結果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		
   //調用dd(E e)方法,默認在列表的尾部添加
		list.add(10);
		System.out.println(list);
   //結果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
   //get方法獲取某個角標下的值,注意角標越界喔!
		System.out.println(list.get(10));
	//結果 10
	
	//在該集合中間某角標位置添加一個數,該位置的數並不會被覆蓋,
	//而是從該位置起的元素到最後的元素都向後移一個位置,再把要添加的數添加進去,哪怕元素重複也會添加進去
	//注意:在指定添加位置的時候,位置下標的取值在[(該集合的首元素下標-1)且要大於等於零,該集合的長度]
	//如果指定的下標超過這個範圍就會發生錯誤
		list.add(4,11);
		list.add(4,11);
		System.out.println(list);
	//結果 [0, 1, 2, 3, 11, 11, 4, 5, 6, 7, 8, 9, 10]
		
	//獲得該集合的長度
		System.out.println(list.size());
	//結果 13
		
	  //indexOf方法,從左右往右獲得指定元素的第一次出現的位置下標
		System.out.println(list.indexOf(11));
	 //結果 4
		
//lastIndexOf方法是獲得指定元素的最後一次出現的位置下標,相當於是從後往前查找指定元素第一次出現的位置下標
		System.out.println(list.lastIndexOf(11));
	  //結果5
		
        //有兩種remove方法
		//remove(int index)  移除列表中指定位置的元素
		//remove(Object e)   從此列表中移除第一次出現的指定元素
		//因爲泛型E-Integer,所以的參數容易混淆
		//因此如果直接調用remove方法並傳入一個值,我們自己可能想移出11這個元素,但是這裏會默認是移出角標爲11所對應的元素9
		System.out.println(list.remove(11));
	 //結果 9
		System.out.println(list);
	//結果  [0, 1, 2, 3, 11, 11, 4, 5, 6, 7, 8, 10]

	//因此要移出某個元素,必須創建該元素的對象再移出,但是它返回的結果是Boolean類型,表示是否移出成功
		System.out.println(list.remove(new Integer(11)));
	//結果 true
		System.out.println(list);
	//結果 [0, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10] ,當然只會移出一個

	//set方法用指定元素去替換指定位置的元素,這裏是覆蓋,元素不會移動
		list.set(0, 666);
		System.out.println(list);
	//結果  [666, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10] 
		
	//subList方法用於截取該集合的子串,需要指明從哪個位置開始,截取多少,
	//當然這個截取的大小不能超過集合總長,指定的位置不能越過集合的角標範圍
	//這個方法只是截取複製出來,對原集合不受影響
		System.out.println(list.subList(0, 3));
	//結果  [666, 1, 2]
		System.out.println(list);
    //截取後原集合的結果不變 [666, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10]

		
	//list集合也有迭代器Iterator方法,用來遍歷集合的元素
		
		//但是Iterator在迭代集合的過程中,對集合是不可進行修改的,即不能調用其相應的方法進行操作
		
	//這段代碼雖然編譯時不會報錯,但是在運行時就會出錯ConcurrentModificationException,表示不可修改
		
		/*Iterator<Integer> it=list.iterator();
		while(it.hasNext()){
			Integer number=it.next();
			if(number==3){
				//ConcurrentModificationException
				list.remove(new Integer(3));
			}else{
				System.out.println(number);
			}
		}*/

	//爲解決這一問題,list接口增加了ListIterator方法,有兩種選擇:
	//可以獲取ListIterator()方法,返回此列表元素的列表迭代器(按適當順序)。
	//listIterator(int index)方法 ,返回列表中元素的列表迭代器(按適當順序),從列表的指定位置開始。
	  //因此,可以在迭代集合的過程中,通過ListIterator對集合進行修改
		ListIterator<Integer> it2=list.listIterator();
		while(it2.hasNext()){
			Integer number=it2.next();
			if(number==11){
			//這裏的remove()方法是ListIterator內部的方法
				it2.remove();
			}else{
				System.out.println(number);
			}
		}
	//迭代完成的結果 [666, 1, 2, 3, 4, 5, 6, 7, 8, 10]
		System.out.println(list);
	//修改後的原集合 [666, 1, 2, 3, 4, 5, 6, 7, 8, 10]

	//當然list提供角標訪問,可以直接用循環訪問下標獲取集合的元素
		for(int i=0;i<list.size();i++){
			System.out.println(list.get(i));
		}
	//結果  [666, 1, 2, 3, 11, 4, 5, 6, 7, 8, 10]
	}
}

ArrayList<E>類

ArrayList基於數組實現的、且容量和大小是可變的、但是在線程上是不同步的(線程問題會在後面進行介紹)。

基於數組實現的鏈表的優點是:查改快;缺點爲:增刪慢。ArrayList的方法有很多,大多都和它的父接口中的方法用法相同(參照上面List中的方法和collection中的方法),下面是它的一些基本方法的測試和說明。

import java.util.ArrayList;

public class Main {
	public static void main(String[] args) {
		
		//這裏還是採用Integer類來進行測試方便理解。因爲ArrayList是一個類,因此可以創建自己的對象
		/*
		 * ArrayList()有三個構造方法:
		 * ArrayList()   構造一個初始容量爲 10 的空列表。 
		 * ArrayList(Collection<? extends E> c)(該方法不常用)
		 *   構造一個包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。 
		 * ArrayList(int initialCapacity)  構造一個具有指定初始容量的空列表。 
		 */
	//這裏創建的是一個指定初始容量爲20的空列表對象
		ArrayList<Integer> list=new ArrayList<Integer>(20);
		for(int i=1;i<=10;i++){
			list.add(i); //add方法,將指定的元素添加到此列表的尾部。
		}
		System.out.println(list);
	//結果 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
	 // trimToSize()方法,將此 ArrayList 實例的容量調整爲列表的當前大小。
	//此方法不能用結果來測試,原因是size()方法是獲取當前集合的有效元素的大小
	//在ArrayList當中沒有獲取當前容量的方法,因爲這是在內存中處理的,並沒有返回結果,因此無法根據結果來測試
		list.trimToSize();
	
	//ensureCapacity方法是, 如有必要,增加此 ArrayList 實例的容量,以確保它至少能夠容納最小容量參數所指定的元素數。
	//此方法與trimToSize方法相對,當trimToSize方法減少容量時ensureCapacity增加容量(也可以減少)
	//雖然在這裏,我們看不到結果,但是還是將當前的容量改回來,方便後面的方法測試
		list.ensureCapacity(20);

	//clone()方法,返回此 ArrayList 實例的淺表副本。相當於把原列表複製一份到新的一個列表
	 //在複製時,還要進行強制轉換,因爲clone()方法返回的類型是object對象
		ArrayList<Integer> list2=(ArrayList<Integer>) list.clone();
		System.out.println(list2);
	//複製之後的list2結果  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
	//調用equals方法比較兩個列表的內容,結果爲true
		System.out.println(list.equals(list2));
		
	//雖然內容一樣,但是它還是兩個對象,用==比較兩個列表對象的地址,結果爲false
		System.out.println(list==list2);
		
  //toArray()方法,按適當順序(從第一個到最後一個元素)返回包含此列表中所有元素的數組;
	//返回數組的運行時類型是指定數組的運行時類型
		Object[] numbers=list.toArray();
	//通過toArray方法,將該列表轉爲數組,然後用遍歷數組的方法進行遍歷該列表的元素
		for(int i=0;i<numbers.length;i++){
			System.out.println(numbers[i]);
		}
	//結果 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
	}
}

LinkedList<E>類

LinkedList是基於鏈表實現、但即可當做列表使用、也可當做棧使用,還可當做雙端隊列使用,且它的線程也是不同步的

基於鏈表實現的列表的優點是:增刪快;缺點爲:查改慢,LinkedList與ArrayList同爲List的子類,大多也都和它的父接口中的方法用法相同(參照上面List中的方法和collection中的方法),下面是它的一些基本方法的測試和說明。

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

public class Main {
	public static void main(String[] args) {
	//LinkedList可用於列表、堆棧和隊列使用
		LinkedList<Integer> list=new LinkedList<Integer>();
		
	//當做列表使用
		for(int i=0;i<10;i++){
			list.add(i); //add方法,將指定元素添加到此列表的結尾。
		}
		System.out.println(list);
	//結果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
	
	//clear方法,從此列表中移除所有元素。
		list.clear();  
		System.out.println(list);
	//結果  []
		
		for(int i=0;i<10;i++){
   //addFirst方法,將指定元素插入此列表的開頭。還有一個addLast方法, 將指定元素添加到此列表的結尾。
		//此方法既可以當做列表使用,也可當做堆棧使用
			list.addFirst(i);
		}
		System.out.println(list);
		
	//結果  [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
		list.clear();
		
	//當做堆棧使用
		for(int i=0;i<10;i++){
	//push方法,將元素推入此列表所表示的堆棧。
			list.push(i);	
		}
		System.out.println(list);
	//結果  [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
		list.clear();
		
	//當做隊列使用
		for(int i=0;i<10;i++){
	//offer方法, 將指定元素添加到此列表的末尾(最後一個元素)。
    //與列表使用相同,還有offerFirst方法,在此列表的開頭插入指定的元素
	//offerLast方法,在此列表末尾插入指定的元素。
			list.offer(i);	
		}
		System.out.println(list);
   //結果  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		
	//get方法,返回此列表中指定位置處的元素。此外還有:
	//getFirst():返回此列表的第一個元素。
	//getLast():返回此列表的最後一個元素
		System.out.println(list.get(3));
	//結果 3
		
		
	 //在LinkedList中,提供descendingIterator()方法,返回以逆向順序在此雙端隊列的元素上進行迭代的“迭代器”。
	 //默認從表尾開始遍歷
		Iterator<Integer> it=list.descendingIterator();
		while(it.hasNext()){
			System.out.print(it.next());
		}
	//結果 9876543210
		System.out.println();
	 //除此之外,LinkedList也存在listIterator(int index)方法,
	 //返回此列表中的元素的“列表迭代器”(按適當順序),從列表中指定位置開始。可以默認從表頭開始遍歷或者指定起始位置開始
	//在ListIterator<E>接口中,比Iterator<E>接口多了一種遍歷的方法,逆序遍歷
	//previous(): 返回列表中的前一個元素。
	//hasPrevious(): 如果以逆向遍歷列表,列表迭代器有多個元素,則返回 true。
	//如果默認從表頭開始 則調用previous方法沒元素,只能用next方法
	//如果從指定位置開始,可以用previous方法,也可以用next方法
		ListIterator<Integer> it2=list.listIterator(5);
		while(it2.hasPrevious()){
			System.out.print(it2.previous());
		}
	//結果  43210
		
	//注意:Iterator 只能從表頭開始 且只能用next
	}
}

Vector<E>類

Vector是基於數組的、可變長的、線程同步的集合、(同步意味着線程安全->有函數鎖->每次調用函數得先判斷鎖是否被佔用,一般在多線程的情況下用和StringBuffer比較像),缺點是都慢,但是一般這個藉口不常用,常用的是它的實現子類Stack,基於棧實現,Vector的改裝。關於Stack的介紹和方法的使用,在前面已經介紹過,請參考:

https://blog.csdn.net/weixin_45432742/article/details/99850913

至此有關List的子類和方法的使用就介紹到這裏。現在我們來總結一下迭代器,如圖:

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