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的子類和方法的使用就介紹到這裏。現在我們來總結一下迭代器,如圖: