目錄
一. List
1.1 什么是List
1.2 List 的常見方法
1.3 List 的使用
二. 順序表
2.1 什么是順序表
2.2?實現自己的順序表
2.2.1 接口實現
2.2.2 實現順序表
三. ArrayList
3.1?ArrayList簡介
3.2 ArrayList的三個構造方法
3.2.1 無參構造方法
3.2.2 帶一個參數的構造方法
3.3 ArrayList的常見方法
3.4?ArrayList 的遍歷
3.4.1 直接打印
3.4.2?for循環遍歷
3.4.3 借助for-each遍歷
3.4.4 迭代器遍歷
一. List
1.1 什么是List
在集合框架中,List是一個接口,繼承自Collect
站在數據結構的角度來看,List就是一個線性表,即n個具有相同類型元素的有限序列,在該序列上可以執行增刪改查以及變量等操作
1.2 List 的常見方法
下面是List接口中的一些常見方法
1.3 List 的使用
由于List 是一個接口,不能直接實例化對象,但是在集合框架中,ArrayList和LinkedList都實現了List接口
二. 順序表
2.1 什么是順序表
順序表是用一段物理地址連續的存儲單元依次存儲數據元素的線性結構,一般采用數組存儲,ArrayList就是順序表的一種實現形式
2.2?實現自己的順序表
在學習ArrayList之前,我們可以先試著寫一個自己實現的順序表,能幫助我們在使用ArrayList的方法以及了解它時更加得心應手
2.2.1 接口實現
public class IList {public void add(int data) { }// 在 pos 位置新增元素public void add(int pos, int data) { }// 判定是否包含某個元素public boolean contains(int toFind) { return true; }// 查找某個元素對應的位置public int indexOf(int toFind) { return -1; }// 獲取 pos 位置的元素public int get(int pos) { return -1; }// 給 pos 位置的元素設為 valuepublic void set(int pos, int value) { }//刪除第?次出現的關鍵字keypublic void remove(int toRemove) { }// 獲取順序表?度public int size() { return 0; }// 清空順序表public void clear() { }// 打印順序表,注意:該?法并不是順序表中的?法,為了?便看測試結果給出的public void display() { }
}
下面,我們自己的順序表將會實現并重寫IList中的所有方法
2.2.2 實現順序表
import java.util.Arrays;class EmptyListException extends RuntimeException{public EmptyListException(String message) {super(message);}
}class IndexException extends RuntimeException{public IndexException(String message) {super(message);}
}
public class MyArrayList implements IList{public int arr[];public final int Initial_Capacity=10;public int Used_size;public MyArrayList() {this.arr = new int [Initial_Capacity];}@Overridepublic void add(int data) {if(is_full()){grow();}this.arr[Used_size]=data;Used_size++;}@Overridepublic void add(int pos, int data) {if(is_full()){grow();}checkPos(pos);for (int i =Used_size-1; i>=pos; i--) {arr[i+1]=arr[i];}arr[pos]=data;Used_size++;}public boolean is_full(){if(arr.length==Used_size){return true;}return false;}public void grow(){this.arr= Arrays.copyOf(arr,arr.length*2);}@Overridepublic boolean contains(int toFind) {for (int i = 0; i <arr.length; i++) {if(arr[i]==toFind){return true;}}return false;}@Overridepublic int indexOf(int toFind) {for (int i = 0; i <arr.length; i++) {if (arr[i] == toFind) {return i;}}return -1;}@Overridepublic int get(int pos) {check(pos);isEmpty();return arr[pos];}public void check(int pos){if(pos<0||pos>=Used_size){throw new IndexException(pos+"位置下標訪問不合法");}}public void checkPos(int pos){if(pos<0||pos>Used_size){throw new IndexException(pos+"位置下標訪問不合法");}}public void isEmpty(){if(Used_size==0){throw new EmptyListException("該表為空表");}}@Overridepublic void set(int pos, int value) {check(pos);arr[pos]= value;}@Overridepublic void remove(int toRemove) {int index=indexOf(toRemove);if(index==-1){System.out.println("沒有要刪除的元素");return;}for (int i =index; i <Used_size-1; i++) {arr[i]=arr[i+1];}Used_size--;}@Overridepublic int size() {return Used_size;}@Overridepublic void clear() {for (int i = 0; i <Used_size; i++) {arr[i]=0;}Used_size=0;//如果數組中的是引用數據類型的元素時,一定要將其全部置為null(避免空間造成浪費)}@Overridepublic void display() {for (int i = 0; i <this.Used_size; i++) {System.out.print(arr[i]+" ");}System.out.println();}
}
注意:
- 在刪除和特定位置添加元素的方法中采用的是覆蓋的思想,下面是添加元素到特定位置的流程圖(將6添加到3下標位置)
- 在 clear()中如果要清空的順序表是存放引用數據類型的話,一定要將其全部設置為null
三. ArrayList
3.1?ArrayList簡介
在集合框架中,ArrayList是一個普通的類,實現了List接口。具體框架如下:
注意:
- ArrayList是以泛型的形式實現的,使用時必須要先實例化
- ArrayList底層是一段連續的空間,并且可以動態擴容,是一個動態類型的順序表
3.2 ArrayList的三個構造方法
3.2.1 無參構造方法
下面是ArrayList類中的源碼截取:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}private Object[] grow(int minCapacity) {int oldCapacity = elementData.length;if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {int newCapacity = ArraysSupport.newLength(oldCapacity,minCapacity - oldCapacity, /* minimum growth */oldCapacity >> 1 /* preferred growth */);return elementData = Arrays.copyOf(elementData, newCapacity);} else {return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];}}public void add(int index, E element) {rangeCheckForAdd(index);modCount++;final int s;Object[] elementData;if ((s = size) == (elementData = this.elementData).length)elementData = grow();System.arraycopy(elementData, index,elementData, index + 1,s - index);elementData[index] = element;size = s + 1;}
解釋:
這里的 elementData 是 ArrayList 內部用于存儲元素的數組,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是一個空數組。當使用無參構造方法創建 ArrayList 時,實際上只是將 elementData 初始化為一個空數組。當向 ArrayList 中添加第一個元素(僅限添加的第一個元素)時, ArrayList 會自動擴容,將數組容量擴展為默認容量(通常是10)。
3.2.2 帶一個參數的構造方法
- ArrayList(int initialCapacity)
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);}}
解釋:通過這個構造方法,當傳入一個大于0的整數作為參數時, ArrayList 會創建一個具有指定容量的數組來存儲元素,這樣可以在已知元素大概數量的情況下,減少數組擴容的次數,提高性能。如果傳入0,則使用一個空數組。如果傳入負數,會拋出異常,因為容量不能為負
- ArrayList(Collection<? extends E> c)
public ArrayList(Collection<? extends E> c) {Object[] a = c.toArray();if ((size = a.length) != 0) {if (c.getClass() == ArrayList.class) {elementData = a;} else {elementData = Arrays.copyOf(a, size, Object[].class);}} else {// replace with empty array.elementData = EMPTY_ELEMENTDATA;}}
解釋:使用集合類來構造ArrayList,將該集合類中的所有元素用來構造ArrayList,和ArrayList中的 addAll(Collection<? extends E> c)的作用類似,其中Collection<? extends E> c?表示可以傳入實現了Collection接口并且泛型參數類型是E/E子類的集合類,下面是一個例子:這里不是一個集合類一個元素(與List的嵌套不同)
public static void main(String[] args) {ArrayList<Integer> list0=new ArrayList<>();list0.add(1);list0.add(2);ArrayList<Integer> list1=new ArrayList<>();list1.add(1);list1.add(2);ArrayList<Integer> list=new ArrayList<>(list0);//使用List0這個集合類來構造listlist.add(100);//向list中添加元素list.addAll(list1); //向list中來添加集合類System.out.println(list);System.out.println(list.size());}打印結果:
[1, 2, 100, 1, 2]
5
public static void main(String[] args) {ArrayList<ArrayList<Integer>> lists=new ArrayList<>();ArrayList<Integer> list3=new ArrayList<>();list3.add(1);list3.add(2);list3.add(3);lists.add(list3);System.out.println(lists.size());}打印結果:1
3.3 ArrayList的常見方法
ArrayList的方法很多,以下只列舉常見的幾種:
注意:
- LIst<E>subList(int formIndex,int toIndex) 這個方法要重點注意(是個坑),1. 這個方法的返回值實際上是截取list部分的首地址,如果改變subList中的元素,被截取的原list中的元素也會發生改變,2. 截取部分是[? )
3.4?ArrayList 的遍歷
3.4.1 直接打印
public static void main(String[] args) {ArrayList<Integer> list3=new ArrayList<>();list3.add(1);list3.add(2);list3.add(3);System.out.println(list3);}打印結果:[1,2,3]
3.4.2?for循環遍歷
public static void main(String[] args) {ArrayList<Integer> list3=new ArrayList<>();for (int i = 0; i <list3.size(); i++) {System.out.print(list3.get(i)+" ");}System.out.println();}打印結果:1 2 3
3.4.3 借助for-each遍歷
public static void main(String[] args) {ArrayList<Integer> list3=new ArrayList<>();list3.add(1);list3.add(2);list3.add(3);for(Integer integer: list3){System.out.print(integer+" ");}}打印結果:1 2 3
3.4.4 迭代器遍歷
public static void main(String[] args) {ArrayList<Integer> list3=new ArrayList<>();list3.add(1);list3.add(2);list3.add(3);Iterator<Integer> it=list3.iterator();while(it.hasNext()){System.out.print(it.next()+" ");}System.out.println();ListIterator<Integer> it2=list3.listIterator(list3.size());while(it2.hasPrevious()){ //倒著打印System.out.print(it2.previous()+" ");}System.out.println();ListIterator<Integer> it3=list3.listIterator(1);while(it3.hasNext()){ //從指定位置打印System.out.print(it3.next()+" ");}}打印結果:
1 2 3
3 2 1
2 3
注意:
- 原理:Arraylist中重寫了literable接口中iterator()方法(),該方法的返回值是一個實現了Iterator接口的類Itr(Itr類是一個定義在ArrayList類內部的的一個私有內部類)的實例化對象(Iterator接口沒有繼承任何接口),通過這個對象可以調用Iterator接口的各種方法進行遍歷
- ListIterator接口?實際上擴展了 Iterator接口,新增hasPrevious()和Previous()等方法,且在調用ListIterator()可傳入參數,從特定位置進行打印,使得打印更加靈活
- ArrayList的擴容機制是擴1.5倍