各種原因,前兩年做C語言去了,現(xiàn)在重新做JAVA, 感覺自己基礎(chǔ)很不扎實,要好好學(xué)習(xí)啦, 先從簡單的開始~
以下內(nèi)容基于jdk1.7.0_79源碼;
什么是ArrayList
可以簡單的認為是一個動態(tài)數(shù)組;實際上ArrayList就是用數(shù)組實現(xiàn)的,長度不夠時,調(diào)用Arrays.copyOf方法,拷貝當(dāng)前數(shù)組到一個新的長度更大的數(shù)組;
ArrayList特點
隨機訪問速度快,插入和移除性能較差(數(shù)組的特點);
支持null元素;
有順序;
元素可以重復(fù);
線程不安全;
ArrayList繼承的類和實現(xiàn)的接口
如下圖,是與ArrayList相關(guān)的接口和類,下面將一一介紹各個接口和類中的方法;
PS:ArrayList中的方法主要是由Collection接口和List接口定義的;

Iterable接口
實現(xiàn)此接口以便支持foreach語法,如下代碼,ArrayList可以直接使用foreach語句遍歷元素:
View CodeCollection接口
int size()方法:
返回集合的大小,在ArrayList類中有一個int類型的size私有屬性,當(dāng)調(diào)用size方法時,直接返回該屬性;
boolean isEmpty()方法:
判斷集合是否為空,在ArrayList中,通過判斷size == 0來判斷集合是否為空;
boolean contains(Object o)方法:
判斷集合是否含有對象o,在ArrayList中,通過判斷indexOf(o) >= 0來判斷是否含有o對象;
查看indexOf(o)方法,代碼如下,主要功能是返回元素第一次出現(xiàn)時的下標(biāo)索引,所以當(dāng)下標(biā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;
? ? }
注意這里的相等判斷,調(diào)用的是o對象的equals方法,所以在調(diào)用contains方法時,要特別關(guān)注集合中對象的equals方法,是否有被重寫過,如Integer、String的equals方法是被重寫過的,一般我們自己定義的對象,如果沒重寫equals的話,默認調(diào)用的是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
? ? ? ?
? ? }
}
Iterator<E> iterator()方法:
返回一個迭代器對象,用于遍歷集合,事實上,ArrayList類里有兩個內(nèi)部類ArrayList.Itr和ArrayList.ListItr,分別對應(yīng)Iterator迭代器和ListIterator迭代器,后者比前者功能更加強大;從ArrayList.ListItr繼承自ArrayList.Itr就可以看出來,ListIterator迭代器支持更多的操作,如判斷前面還有沒有元素,即hasPrevious()方法,等;
Object[] toArray()方法:
將集合ArrayList轉(zhuǎn)換成Object數(shù)組,有時候需要用到數(shù)組的一些api時,可以使用該方法,注意返回的結(jié)果是Object類型的數(shù)組,如果想返回指定類型的數(shù)組,可以使用以下方法,<T> T[] toArray(T[] a);
<T> T[] toArray(T[] a)方法:
集合轉(zhuǎn)數(shù)組,返回指定類型的數(shù)組,注意入?yún)[] a需要指定數(shù)組存儲的空間,返回值為指定類型的數(shù)組;舉個例子,假如有一個Integer類型的集合,如果想把它轉(zhuǎn)換成Integer類型的數(shù)組,可以這樣寫:Integer[] arr = list.toArray(new Integer[list.size()]);
boolean add(E e)方法:
在集合最后面增加一個元素,在ArrayList中,其實現(xiàn)就是在其內(nèi)部數(shù)組后面增加一個元素,不過要先保證內(nèi)部數(shù)組長度足夠,如下代碼:
? ? public boolean add(E e) {
? ? ? ? ensureCapacityInternal(size + 1);? // Increments modCount!!
? ? ? ? elementData[size++] = e;
? ? ? ? return true;
? ? }boolean remove(Object o)方法:
在集合中移除對象o,在ArrayList中,其實現(xiàn)較add方法復(fù)雜,涉及空對象判斷,equals比較,數(shù)組移動等,性能相對較差;
boolean containsAll(Collection<?> c)方法:
判斷是否包含集合c中的所有元素,在ArrayList中,其實現(xiàn)方法是遍歷集合c中的每一個元素,調(diào)用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中的所有元素加到目標(biāo)集合中去,在ArrayList中,其實現(xiàn)是先將集合c轉(zhuǎn)換成數(shù)組,然后通過數(shù)組拷貝實現(xiàn);
boolean removeAll(Collection<?> c)方法:
移除目標(biāo)集合中含有‘集合c中元素’的所有元素,在ArrayList中,最終還是操作數(shù)組,性能相對較差;
boolean retainAll(Collection<?> c)方法:
移除目標(biāo)集合中‘不包含集合c中元素’的所有元素,在ArrayList中removeAll方法和retainAll方法都是通過調(diào)用ArrayList的batchRemove方法來實現(xiàn)的,后續(xù)詳細了解該方法的實現(xiàn);
void clear()方法:
移除目標(biāo)集合中的所有元素,在ArrayList中,就是將其內(nèi)部數(shù)組所有元素賦null;
boolean equals(Object o)和int hashCode()方法
在ArrayLisy中,上面兩個方法都被重寫,equals方法依次取出集合中的所有元素進行比較,通過元素的equals方法,判斷是否相等,全部相等返回true;
hashCode方法的計算是通過所有元素的hashCode計算得到;順便說下hashcode,在java中隨處可見,一般用在HashMap, Hashtable, HashSet等等中,可用于減少equals方法的調(diào)用,快速訪問元素等,其實就是散列表的概念,如比較元素先比較其hashcode,如果hashcode不相等,那么這兩個元素肯定不相等,也就不用調(diào)用其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);
? ? ? ?
? ? }
}
List接口
除了Collection中定義的方法為,該接口增加了以下方法
boolean addAll(int index, Collection<? extends E> c);
在ArrayList中,該方法是在指定位置處增加一個集合中的所有元素,該操作涉及數(shù)組移動;
E get(int index);
返回下標(biāo)為index的元素;
E set(int index, E element);
改變下標(biāo)為index的元素的值
void add(int index, E element);
在下標(biāo)為index的地方插入元素element,該操作涉及數(shù)組移動;
E remove(int index);
移除下標(biāo)為index的元素,該操作涉及數(shù)組移動;
int indexOf(Object o);
返回元素o的最小下標(biāo),通過調(diào)用o的equals方法與集合中的元素進行比較;
int lastIndexOf(Object o);
返回元素o的最大下標(biāo),通過調(diào)用o的equals方法與集合中的元素進行比較;
ListIterator<E> listIterator();
返回listIterator迭代器,該迭代器支持向前操作;
ListIterator<E> listIterator(int index);
返回listIterator迭代器,從特定的位置開始,該迭代器支持向前操作;
List<E> subList(int fromIndex, int toIndex);
返回下標(biāo)在fromIndex和toIndex之間的元素集合;
demo代碼:以上方法的簡單使用:
View CodeRandomAccess, Cloneable, java.io.Serializable接口
這三個接口是標(biāo)識接口,里面都是空的;
RandomAccess標(biāo)識其支持快速隨機訪問;
Cloneable標(biāo)識其支持對象復(fù)制;
Serializable標(biāo)識其可序列化;
AbstractCollection類
大部分方法前面已經(jīng)說明過了,不過該類下的contains方法、toArray方法等,遍歷的時候都是使用更加通用的迭代器方式進行遍歷;
AbstractList類
大部分方法前面已經(jīng)說明過了,不過該類中有兩個私有內(nèi)部類Itr和ListItr,對應(yīng)的分別是兩個迭代器;
ArrayList類
ArrayList的具體實現(xiàn)
成員屬性:
private static final int DEFAULT_CAPACITY = 10;//初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};//空ArrayList實例共享的一個空數(shù)組
private transient Object[] elementData; //真正存儲ArrayList中的元素的數(shù)組;
private int size;//存儲ArrayList的大小,注意不是elementData的長度;
除了其父接口定義的方法外,該類增加了以下方法
public ArrayList(int initialCapacity):
構(gòu)造函數(shù),指定初始大小
public ArrayList()
構(gòu)造函數(shù),使用共享的EMPTY_ELEMENTDATA空數(shù)組
public ArrayList(Collection<? extends E> c)
構(gòu)造函數(shù),通過集合初始化ArrayList
public void trimToSize()
節(jié)省空間用的,ArrayList是通過數(shù)組實現(xiàn)的,大小不夠時,增加數(shù)組長度,有可能出現(xiàn)數(shù)組長度大于ArrayList的size情況;
public void ensureCapacity(int minCapacity)
保證ArrayList能容納minCapacity個元素;
私有方法
略
ArrayList內(nèi)部數(shù)組擴容
查看ArrayList的add源碼方法,如下:
? ? public boolean add(E e) {
? ? ? ? ensureCapacityInternal(size + 1);? // Increments modCount!!
? ? ? ? elementData[size++] = e;
? ? ? ? return true;
? ? }在往ArrayList增加e對象前,要先保證內(nèi)部數(shù)組空間足夠,即調(diào)用ensureCapacityInternal判斷,查看其代碼,如下:
? ? private void ensureCapacityInternal(int minCapacity) {
? ? ? ? if (elementData == EMPTY_ELEMENTDATA) {
? ? ? ? ? ? minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
? ? ? ? }
? ? ? ? ensureExplicitCapacity(minCapacity);
? ? }
入?yún)inCapacity為ArrayList要保證的最小空間大小,首先判斷內(nèi)部數(shù)組elementData是否是初始的空數(shù)組(當(dāng)ArrayList是空實例的情況),如果是的話,且minCapacity比DEFAULT_CAPACITY小,則設(shè)minCapacity為默認的初始容量大小DEFAULT_CAPACITY;接著調(diào)用ensureExplicitCapacity方法,查看其代碼,如下:
? ? private void ensureExplicitCapacity(int minCapacity) {
? ? ? ? modCount++;
? ? ? ? // overflow-conscious code
? ? ? ? if (minCapacity - elementData.length > 0)
? ? ? ? ? ? grow(minCapacity);
? ? }
首先,是對修改次數(shù)modCount加一,這里的modCount給ArrayList的迭代器使用的,在并發(fā)操作被修改時,提供快速失敗行為(保證modCount在迭代期間不變,否則拋出ConcurrentModificationException異常,可以查看源碼859行),接著判斷minCapacity是否大于當(dāng)前ArrayList內(nèi)部數(shù)組長度,大于的話調(diào)用grow方法對內(nèi)部數(shù)組elementData擴容,grow方法代碼如下:
? ? private void grow(int minCapacity) {
? ? ? ? // overflow-conscious code
? ? ? ? int oldCapacity = elementData.length;
? ? ? ? int newCapacity = oldCapacity + (oldCapacity >> 1);
? ? ? ? if (newCapacity - minCapacity < 0)
? ? ? ? ? ? newCapacity = minCapacity;
? ? ? ? if (newCapacity - MAX_ARRAY_SIZE > 0)
? ? ? ? ? ? newCapacity = hugeCapacity(minCapacity);
? ? ? ? // minCapacity is usually close to size, so this is a win:
? ? ? ? elementData = Arrays.copyOf(elementData, newCapacity);
? ? }
首先,獲取內(nèi)部數(shù)組elementData長度,并對它的大小增加1.5倍(oldCapacity + (oldCapacity >> 1)),賦給newCapacity,當(dāng)newCapacity仍然比minCapacity(要保證的最小空間大?。┬〉臅r候,直接讓newCapacity 等于minCapacity;然后再判斷newCapacity 是不是大于MAX_ARRAY_SIZE,如果大于的話,調(diào)用hugeCapacity方法,處理大容量空間的情況,該方法判斷是否溢出(拋出OutOfMemoryError),以及當(dāng)minCapacity大于MAX_ARRAY_SIZE時,直接返回Integer.MAX_VALUE;最后就是真正地數(shù)組擴容了,調(diào)用Arrays.copyOf方法,拷貝舊的內(nèi)部數(shù)組內(nèi)容到一個新的(長度為newCapacity)的數(shù)組,并更改內(nèi)部數(shù)組elementData的引用為新數(shù)組;
ArrayList遍歷
一般工作中用的比較多的是遍歷操作,ArrayList支持三種方式
- for循環(huán)下標(biāo)遍歷;
- 迭代器(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循環(huán)
? ? ? ? System.out.println("for循環(huán):");
? ? ? ? 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() + " ");
? ? ? ? }
? ? }
}
