オリジナル住所:xeblog.cn/articles/19
本論文では、JDK8でのArrayListの実現を説明します。
ArrayListの概要
ArrayList
アレイは、キュー、内部メンテナンスでありJava数组
、それはアレイの容量が自動的に成長する、動的です。これは、継承AbstractList
と実装List、RandomAccess、Cloneable、Serializable
のインターフェイスを。
ArrayListのの長所と短所
利点
- これは、内部配列要素がアクセスする配列のインデックスを介してランダムアクセスに等しい、ランダム要素は、高効率を得ることであるため、ランダムアクセスをサポートします。
- 要素は、(追加の順に)命じています。
- 自動拡張(利点と欠点の両方)をサポートします。
短所
- スレッド安全ではありません。
- 低効率の自動拡張は、各拡張は、新しい配列にすべての要素を追加する必要があります。
- 配列内の要素を移動するために必要な操作を追加し、削除します。
質問:なぜArrayListを継承AbstractListが、その後、Listインタフェースを実装?
- 答えは、私は、コンテンツの信憑性を区別することはできませんが、天日乾燥を乾かすことができます。
stackoverflow
一部の人々は答えがあると言うJosh Bloch
(のJavaコレクションフレームワーク著)設計ミス、著者は、この設計は価値があると思ったが、後でないことが判明しました。
- 明示的に実装されていないため、場合、メソッド実装されたすべてのインターフェイスを取得するためのJavaリフレクションを使用して簡単に
List
インターフェイスを取得することによって、親クラス、親クラスを取得するときに最初のインターフェイスを取得する必要性を反映して、インターフェイスを。 - 一目に簡単に
ArrayList
実装List
インタフェース(おざなり.GIF)を。 - その他...
フィールドのArrayListの一部
/**
* 默认容量为10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于默认大小的空数组。将此与EMPTY_ELEMENTDATA区分开来,以便在添加第一个元素时知道要膨胀多少。
* 使用无参构造初始化ArrayList时默认的数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储ArrayList元素的数组。添加第一个元素时,如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* 则此数组的长度是默认的10
*/
transient Object[] elementData;
/**
* ArrayList的元素个数
*/
private int size;
复制代码
ArrayListのコンストラクタ
int
コンストラクタの型パラメータ、それが渡されArrayList
た初期の長さ
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 默认的空数组 Object[] EMPTY_ELEMENTDATA = {}
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
复制代码
JDK8引数なしのコンストラクタ
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
复制代码
JDK7引数なしのコンストラクタ
public ArrayList() {
this(10);
}
复制代码
JDK8は、引数なしのデフォルト・コンストラクタを使用して初期化ArrayList
を行っていない、遅延最適化が行われ、add()
方法の前にArrayList
、アレイの実際の大きさや0
、デフォルトの長さのためにのみ最初の加算要素まで、10
アレイの初期化。
コレクションオブジェクトのコンストラクタ、要素のコレクションが含まれている構造体を渡しますArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
复制代码
ArrayListのは、ダイナミックな成長を実現する方法ですか?
初めて目にadd(E e)
する方法
public boolean add(E e) {
// 判断添加此元素时数组是否会超出,超出则增长数组
ensureCapacityInternal(size + 1);
// 添加元素
elementData[size++] = e;
return true;
}
复制代码
/**
* 此方法用于判断当添加这个元素时数组容量是否超出,超出则自动增长
*/
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果数组是通过默认构造方法实例化的,elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 将返回true
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 返回最大的值 ,如果minCapacity大于10则返回minCapacity的值
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
// fail-fast机制,并发修改会抛出异常 throw new ConcurrentModificationException()
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
// 新增元素后的数组长度超过了当前数组长度,所以调用增加数组长度的方法
grow(minCapacity);
}
复制代码
見てくださいgrow(int minCapacity)
方法は知っていることができるようになりArrayList
、自動的に容量を増やす方法
// 分配的最大数组大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 增长后的容量等于旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// MAX_ARRAY_SIZE为int的最大值减8,如果增长后的容量超过该值,则直接返回int的最大值,否则返回该值
if (newCapacity - MAX_ARRAY_SIZE > 0);
newCapacity = hugeCapacity(minCapacity);
// 使用的是Arrays.copyOf()方法将原数组中的元素拷贝到新增数组中,新增数组的长度即是newCapacity
elementData = Arrays.copyOf(elementData, newCapacity);
}
复制代码
ここにあるhugeCapacity(int minCapacity)
方法には、
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
复制代码
JDK6 int newCapacity = (oldCapacity * 3)/2 + 1;
成長能力は、昔の1.5倍の容量の直接成長を使用してJDK8ビット単位1 1.5二重に古いの容量に等しいです。
ArrayListには、手動で音量を調整します
呼び出すことにより、多数の要素を追加する前に、ensureCapacity(int minCapacity)
増加の手動方法にArrayList
容量を増分再割り当ての数を減らすために
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
复制代码
trimToSize()
ArrayListの方法は、実際の素子サイズの容量に調節することができます
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
复制代码
フェイルファストメカニズム
のでArrayList
イテレータのを修正使用しての過程で他のスレッドがあるので、もし、スレッドセーフではないArrayList
、それがスローされますthrow new ConcurrentModificationException()
される例外、fail-fast机制
(フェイルファストを)。判断するためのフィールド、フィールドは、親クラスである各変形例では、フィールドは、フィールドが自動的に1インクリメントされ、イテレータ初期化するための時間になります割り当てられたイテレータ値フィールドを。ArrayListのイテレータ内部実装(一部)
fail-fast机制
modCount
modCount
AbstractList
ArrayList
modCount
modCount
expectedModCount
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
复制代码
実行中にnext()、remove()
メソッドの時間呼び出しcheckForComodification()
を決定するための方法をexpectedModCount
もか否かに等しいmodCount
等しくない、他のスレッドが変更された場合、ArrayList
、それは例外をスローしますthrow new ConcurrentModificationException()
。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
复制代码