各種原因,前兩年做C語言去了,現在重新做JAVA, 感覺自己基礎很不扎實,要好好學習啦, 先從簡單的開始~ 以下內容基於jdk1.7.0_79源碼; 什麼是ArrayList 可以簡單的認為是一個動態數組;實際上ArrayList就是用數組實現的,長度不夠時,調用Arrays.copyOf方法,拷貝
各種原因,前兩年做C語言去了,現在重新做JAVA, 感覺自己基礎很不扎實,要好好學習啦, 先從簡單的開始~
以下內容基於jdk1.7.0_79源碼;
什麼是ArrayList
可以簡單的認為是一個動態數組;實際上ArrayList就是用數組實現的,長度不夠時,調用Arrays.copyOf方法,拷貝當前數組到一個新的長度更大的數組;
ArrayList特點
隨機訪問速度快,插入和移除性能較差(數組的特點);
支持null元素;
有順序;
元素可以重覆;
線程不安全;
ArrayList繼承的類和實現的介面
如下圖,是與ArrayList相關的介面和類,下麵將一一介紹各個介面和類中的方法;
PS:ArrayList中的方法主要是由Collection介面和List介面定義的;
Iterable介面
實現此介面以便支持foreach語法,如下代碼,ArrayList可以直接使用foreach語句遍歷元素:
package com.pichen.basis.col; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < 10; i++){ list.add(i); } //foreach語法 for(Integer i : list){ System.out.print(i.toString() + " "); } } }View Code
Collection介面
int size()方法:
返回集合的大小,在ArrayList類中有一個int類型的size私有屬性,當調用size方法時,直接返回該屬性;
boolean isEmpty()方法:
判斷集合是否為空,在ArrayList中,通過判斷size == 0來判斷集合是否為空;
boolean contains(Object o)方法:
判斷集合是否含有對象o,在ArrayList中,通過判斷indexOf(o) >= 0來判斷是否含有o對象;
查看indexOf(o)方法,代碼如下,主要功能是返回元素第一次出現時的下標索引,所以當下標索引大於等於0時,表示集合中存在該元素:
public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
註意這裡的相等判斷,調用的是o對象的equals方法,所以在調用contains方法時,要特別關註集合中對象的equals方法,是否有被重寫過,如Integer、String的equals方法是被重寫過的,一般我們自己定義的對象,如果沒重寫equals的話,預設調用的是Object的equals方法,舉個例子,看一下就明白了:
package com.pichen.basis.col; import java.util.ArrayList; import java.util.List; class Dog{ } public class ContainsTest { public static void main(String[] args) { List<Dog> dogList = new ArrayList<Dog>(); Dog dog1 = new Dog(); Dog dog2 = new Dog(); dogList.add(dog1); System.out.println(dogList.contains(dog2));//false List<String> strList = new ArrayList<String>(); strList.add("teststr"); String str = new String("teststr"); System.out.println(strList.contains(str));//true } }View Code
Iterator<E> iterator()方法:
返回一個迭代器對象,用於遍歷集合,事實上,ArrayList類里有兩個內部類ArrayList.Itr和ArrayList.ListItr,分別對應Iterator迭代器和ListIterator迭代器,後者比前者功能更加強大;從ArrayList.ListItr繼承自ArrayList.Itr就可以看出來,ListIterator迭代器支持更多的操作,如判斷前面還有沒有元素,即hasPrevious()方法,等;
Object[] toArray()方法:
將集合ArrayList轉換成Object數組,有時候需要用到數組的一些api時,可以使用該方法,註意返回的結果是Object類型的數組,如果想返回指定類型的數組,可以使用以下方法,<T> T[] toArray(T[] a);
<T> T[] toArray(T[] a)方法:
集合轉數組,返回指定類型的數組,註意入參T[] a需要指定數組存儲的空間,返回值為指定類型的數組;舉個例子,假如有一個Integer類型的集合,如果想把它轉換成Integer類型的數組,可以這樣寫:Integer[] arr = list.toArray(new Integer[list.size()]);
boolean add(E e)方法:
在集合最後面增加一個元素,在ArrayList中,其實現就是在其內部數組後面增加一個元素,不過要先保證內部數組長度足夠,如下代碼:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
boolean remove(Object o)方法:
在集合中移除對象o,在ArrayList中,其實現較add方法複雜,涉及空對象判斷,equals比較,數組移動等,性能相對較差;
boolean containsAll(Collection<?> c)方法:
判斷是否包含集合c中的所有元素,在ArrayList中,其實現方法是遍歷集合c中的每一個元素,調用contains方法,判斷集合是否包含該元素,只要有一個不包含就返回false,如下代碼:
public boolean containsAll(Collection<?> c) { for (Object e : c) if (!contains(e)) return false; return true; }
boolean addAll(Collection<? extends E> c)方法:
將集合c中的所有元素加到目標集合中去,在ArrayList中,其實現是先將集合c轉換成數組,然後通過數組拷貝實現;
boolean removeAll(Collection<?> c)方法:
移除目標集合中含有‘集合c中元素’的所有元素,在ArrayList中,最終還是操作數組,性能相對較差;
boolean retainAll(Collection<?> c)方法:
移除目標集合中‘不包含集合c中元素’的所有元素,在ArrayList中removeAll方法和retainAll方法都是通過調用ArrayList的batchRemove方法來實現的,後續詳細瞭解該方法的實現;
void clear()方法:
移除目標集合中的所有元素,在ArrayList中,就是將其內部數組所有元素賦null;
boolean equals(Object o)和int hashCode()方法
在ArrayLisy中,上面兩個方法都被重寫,equals方法依次取出集合中的所有元素進行比較,通過元素的equals方法,判斷是否相等,全部相等返回true;
hashCode方法的計算是通過所有元素的hashCode計算得到;順便說下hashcode,在java中隨處可見,一般用在HashMap, Hashtable, HashSet等等中,可用於減少equals方法的調用,快速訪問元素等,其實就是散列表的概念,如比較元素先比較其hashcode,如果hashcode不相等,那麼這兩個元素肯定不相等,也就不用調用其equals方法了;
demo代碼:以上方法的簡單使用
package com.pichen.basis.col; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class Test { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < 10; i++){ list.add(i); } //直接列印 System.out.println(list.toString()); //size() System.out.println(list.size()); //contains System.out.println(list.contains(2)); //iterator Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next() + " "); } //toArray Object[] objArr = list.toArray(); Integer[] intArr = list.toArray(new Integer[list.size()]); System.out.println("\n" + list.toArray()); //add list.add(5); //remove list.remove(5); System.out.println(list); //containsAll System.out.println(list.containsAll(Arrays.asList(5,6))); //addAll list.addAll(Arrays.asList(555,666)); System.out.println(list); //removeAll list.removeAll(Arrays.asList(555,666)); System.out.println(list); //clear list.clear(); System.out.println(list); } }View Code
List介面
除了Collection中定義的方法為,該介面增加了以下方法
boolean addAll(int index, Collection<? extends E> c);
在ArrayList中,該方法是在指定位置處增加一個集合中的所有元素,該操作涉及數組移動;
E get(int index);
返回下標為index的元素;
E set(int index, E element);
改變下標為index的元素的值
void add(int index, E element);
在下標為index的地方插入元素element,該操作涉及數組移動;
E remove(int index);
移除下標為index的元素,該操作涉及數組移動;
int indexOf(Object o);
返回元素o的最小下標,通過調用o的equals方法與集合中的元素進行比較;
int lastIndexOf(Object o);
返回元素o的最大下標,通過調用o的equals方法與集合中的元素進行比較;
ListIterator<E> listIterator();
返回listIterator迭代器,該迭代器支持向前操作;
ListIterator<E> listIterator(int index);
返回listIterator迭代器,從特定的位置開始,該迭代器支持向前操作;
List<E> subList(int fromIndex, int toIndex);
返回下標在fromIndex和toIndex之間的元素集合;
demo代碼:以上方法的簡單使用:
package com.pichen.basis.col; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ListIterator; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < 10; i++){ list.add(i); } System.out.println(list); //addAll方法 list.addAll(5, Arrays.asList(666,666, 6)); System.out.println(list); //get方法 System.out.println(list.get(5)); //set方法 list.set(5, 55); System.out.println(list.get(5)); //add方法 list.add(0, 555); System.out.println(list); //remove方法 list.remove(0); System.out.println(list); //indexof方法 System.out.println(list.indexOf(6)); //lastIndexOf方法 System.out.println(list.lastIndexOf(6)); //listIterator方法 ListIterator<Integer> listIterator = list.listIterator(); System.out.println(listIterator.hasPrevious()); //listIterator(index)方法 ListIterator<Integer> iListIterator = list.listIterator(5); System.out.println(iListIterator.previous()); //subList方法 System.out.println(list.subList(5, 7)); } }View Code
RandomAccess, Cloneable, java.io.Serializable介面
這三個介面是標識介面,裡面都是空的;
RandomAccess標識其支持快速隨機訪問;
Cloneable標識其支持對象複製;
Serializable標識其可序列化;
AbstractCollection類
大部分方法前面已經說明過了,不過該類下的contains方法、toArray方法等,遍歷的時候都是使用更加通用的迭代器方式進行遍歷;
AbstractList類
大部分方法前面已經說明過了,不過該類中有兩個私有內部類Itr和ListItr,對應的分別是兩個迭代器;
ArrayList類
ArrayList的具體實現
成員屬性:
private static final int DEFAULT_CAPACITY = 10;//初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};//空ArrayList實例共用的一個空數組
private transient Object[] elementData; //真正存儲ArrayList中的元素的數組;
private int size;//存儲ArrayList的大小,註意不是elementData的長度;
除了其父介面定義的方法外,該類增加了以下方法
public ArrayList(int initialCapacity):
構造函數,指定初始大小
public ArrayList()
構造函數,使用共用的EMPTY_ELEMENTDATA空數組
public ArrayList(Collection<? extends E> c)
構造函數,通過集合初始化ArrayList
public void trimToSize()
節省空間用的,ArrayList是通過數組實現的,大小不夠時,增加數組長度,有可能出現數組長度大於ArrayList的size情況;
public void ensureCapacity(int minCapacity)
保證ArrayList能容納minCapacity個元素;
私有方法
略
ArrayList遍歷
一般工作中用的比較多的是遍歷操作,ArrayList支持三種方式
- for迴圈下標遍歷;
- 迭代器(Iterator和ListIterator);
- foreach語句。
package com.pichen.basis.col; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; public class Test { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < 10; i++){ list.add(i); } //直接列印 System.out.println(list.toString()); //for迴圈 System.out.println("for迴圈:"); for(int i = 0; i < list.size(); i++){ System.out.print(list.get(i) + " "); } //foreach System.out.println("\nforeach:"); for(Integer i : list){ System.out.print(i + " "); } //iterator System.out.println("\niterator:"); Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next() + " "); } //listIterator System.out.println("\nlistIterator:"); ListIterator<Integer> listIterator = list.listIterator(); while(listIterator.hasNext()){ System.out.print(listIterator.next() + " "); } System.out.println(); while(listIterator.hasPrevious()){ System.out.print(listIterator.previous() + " "); } } }