ディレクトリ
Javaの、非常に高い周波数のコレクションフレームワークの使用では。正常な発達において、セットは、しばしばために使用される保持他のデータをパッケージ化する、またはそのような配列、スタック、キューのような一般的なデータ構造を実装します。コレクション内のJavaは、2つの主なカテゴリコレクションと地図に分けることができます。コレクションはリスト、キュー、およびセット(下記参照)に分割されています。このブログは、リストのコレクションを導入する主な理由です。
絵。Javaの収集システム
セットの一覧、メイン制御のArrayListとLinkedListの。また、これらの2つのクラスがスレッドセーフではありませんので注意してください。
1. ArrayListに
リストArrayListには、使用するインタフェースの開発プロセスのほとんどを実装するクラスです。配列を実現する基礎となるこのクラスは、配列のサイズを動的に調整することができます。ArrayListのコレクション・ブルームがnullを含む要素、のいずれかのタイプにすることができます。このクラスは、リストストアの配列のサイズを操作する方法を提供します。同様のArrayListのとベクトル、最大の違いは、スレッドセーフではありませんのArrayListとベクトルは、スレッドセーフです。
1.1 ArrayListの建設
以下のArrayListのを作成するには、2つの一般的な方法があります。
//创建一个空的数组,当我们向这个ArrayList中添加第一个元素时,会创建一个默认容量为10的数组
List<String> strList = new ArrayList<String>();
//创建指定长度为16的数组
List<String> strList2 = new ArrayList<String>(16);
ArrayListのを作成するためには、これら二つの概念の容量やサイズの下に配置する必要があります。ArrayListの容量はアレイの長さの基礎となる実装を指し、グループサイズのインデックス番号は、既に要素に格納されています。
さらに、ArrayListのコンストラクタは反復子によって順番に生成される要素の順序によって、コンストラクタで作成された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を使用して、ArrayListのサイズに判断をすることが最善のことなので、いくつかの利点についてがあります。
- メモリ空間を節約する(例えば。私達はちょうど配列に2つの要素を配置する必要があり、新しいArrayListを
(2))。 - アレイの拡張を回避する、に起因する効率が低下します。
1.2メソッドを追加
二つの方法に共通の要素を追加しましたArrayListのです。
- (E eを)追加します。
- addAll(コレクションC <拡張E?>);
- セット(int型のインデックス、EのE)。
- add(E e)方法
public boolean add(E e) {
ensureCapacity(size + 1);//确保对象数组elementData有足够的容量,可以将新加入的元素e加进去
elementData[size++] = e;//加入新元素e,size加1
return true;
}
//扩容的逻辑
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);
}
ArrayListのは、(E eを)追加のロジックを追加し、すべてのソースコードのステッカーを出していない、あなたは下の自分で見ることができ、簡単です。プロセスは、一般付加される:第一の電流配列が空の配列ではない決定、空の配列が、デフォルトの長さを作成する場合、アレイ10の長さであり、要素は、それに加え、空でない配列のArrayList電流が電流の配列を決定した場合もしフル、もし完全な拡張が進行する(拡張論理oldCapa + oldCapacity / 2、長さが最低限必要な長さよりも小さい場合には、最低限必要な長さを使用して、最小値はアレイよりも大きい場合最大の長さは、配列Integer.MAX_VALUEの長さとして使用される)、次いで、要素は、それに加えました。展開プロセスでは、実際にはArrayListのは、長さの配列がnewCapacity、次のように作成されたコードで再作成されます。
//这段代码效率较高,我们开发过程中可以借鉴使用
elementData = Arrays.copyOf(elementData, newCapacity);
- addAll(コレクション<?拡張E> c)の方法
//将集合c中的元素全部添加到ArrayList的尾部
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
//在ArrayList的指定位置添加元素,同时将ArrayList中其他元素右移
//这个方法在使用时需要特别注意index的范围
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
- セット(int型のインデックス、EのE)
//将下标位置的元素替换成新的元素,并且返回原来位置上的元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
1.3メソッドを削除します
一般的に、メソッド名に応じて理解しやすいこれらの方法は、以下の機能を削除するためのメソッドを使用し、ソースコードはここに掲載されていません。
- 公共E削除(int型のインデックス);
- パブリックブール削除(オブジェクトo)。
- パブリックブールのremoveAll(コレクションC <?>);
- 保護された無効removeRange(int型fromIndexの、INTたtoIndex)。
- パブリックブールremoveIf(述語フィルタ<スーパーE?>);
- 明らかます。public void()。
1.4クエリメソッド
ArrayListの要素に一般的に使用される方法が含まれているかどうかを照会するクエリメソッドは、次のクエリがあります。
- パブリックブール(オブジェクトo)が含まれています。
- 公共のintのindexOf(オブジェクトo);
- 公共int型のlastIndexOf。
- 公共Eは、(int型のインデックス)を取得します。
以下のコードから分かるように、2つの要素に等しい標準的な方法によって決定される等しいと等しいです。
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {//返回第一个null的索引
for (int i = 0; i < size; i++)
if (elementData[i] == null)
return i;
} else {//返回第一个o的索引
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;//若不包含,返回-1
}
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size - 1; i >= 0; i--)
if (elementData[i] == null)
return i;
} else {
for (int i = size - 1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
1.5その他の一般的な方法
- 公共一覧
subList(int型fromIndexの、INTたtoIndex); //コンストラクタ配列は、このメソッドを呼び出す前に、コール・パラメータのsubListRangeCheckの正しさを決定するこの方法を作ります - 公共Spliterator
spliterator(); //分割可能イテレータをArrayListSpliterator得る、Spliterator JDK8が並列イテレータに添加されるの効率を増加させる、マルチスレッドの反復で使用することができます - 公共ボイドソート(コンパレータC <スーパーE?>); //は、一定のルールに従って集合の要素をソート
- 公共イテレータ
イテレータ(); //はループの反復のための一般的なイテレータを取得であってもよいです - パブリックオブジェクト[]のtoArray(); //配列にArrayListの要素を設定します。
- 公
T []のtoArray(T [] a)の
1.6 ArrayListの概要
- 容量制限無しのArrayListアレイベースの方法、(最大にInteger.MAX_VALUEです)。
- 要素を削除する能力を低下させない(容量を減らしたい場合は、trimToSize())、あなたは要素を追加(それが何を予測することが最善である)拡張する必要があり、あなたが要素を削除すると、要素は次のGC、位置はnullに設定されて削除されます。これらの要素は、占有するメモリ領域を解放します。
- スレッドセーフ。
- (INTインデックス、Eの要素)を追加します、アレイの場所に指定された時間に要素を追加する場所と必要なすべての要素がコピーバックのピースの背後にあります。
- (INTインデックス)を得る:要素に指定された位置を取得すること直接インデキシング(O(1))することにより得ることができます。
- アレイを横断するのに必要な(オブジェクトO)を除去します。
- (INTインデックス)を除去単に(オブジェクトO)を除去するよりも効率的な、インデックス条件がよいか否かを判断する反復処理する必要がありません。
- 含まれている(E)は、配列トラバーサルが必要です。
2.ベクトル
ベクターおよび底部に非常に類似のArrayListは、配列のセットによって達成されます。ベクターおよびArrayListの最大の違いは、ベクターの多くの方法は、同期が変更に使用され、それがスレッドセーフであるということです。下の2つの主な違いは次のとおりです。
- ArrayListのは、Vectorはスレッドセーフで、非スレッドセーフです。
- 容量を指定しない場合は、コンテナを作成すると、ArrayListには空の配列、最初の要素を作成してから10に容量拡張が追加されます。Vertorを10の容量を持つデフォルトの配列によって作成された容量を作成する際に指定されていない場合。
- 拡張は、ベクトルが2倍に拡張したものであるときArrayL拡大は1.5倍です。
- ArrayListのサポートのシリアライズは、Vectorがサポートされていません。
3. LinkedListの
LinkedListの内部のメンテナンスが二重にリンクされたリストで、次のノード(コードJDK1.8、他の異なるバージョンを持っている)を定義し、ヘッドとテールポインタも定義しています。
...
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
...
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
3.1 LinkedListの建設
//构造一个空的List
public LinkedList() {
}
//通过Collection集合构造LinkedList
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
一般的な操作のリスト3.2
リストのLinkedListの底が実装されているのでLinkedListのは、多くの一般的な操作を提供して、リストをリンク:
- プライベート無効linkFirst(E電子); //第1の補間。
- linkLast(E eを)失う; //尾補間。
- 空linkBefore(E電子、ノード
SUCC); //要素は、ノードEの前に挿入されています - プライベートE unlinkFirst(ノード
F); //ヘッダ要素を削除 - プライベートE unlinkLast(ノード
L); //要素をトレーリング削除 - Eのリンク解除(ノード
X); //非空要素xを削除
3.3操作を追加
- パブリックブールの追加(E電子); //は、リンクリストの末尾に要素を追加します。
- //挿入素子要素の指定された位置は、添字0からカウントされ、公共ボイド追加(INTインデックス、E素子)
- パブリックブールのaddAll(コレクションC <Eを延長するには?>);コレクション全体を追加します
- パブリックブールのaddAll(int型のインデックス、コレクションcは<Eを拡張?>); //インデックス0から算出された所定の位置に設定addが
- 公共Eセット(int型のインデックス、Eの要素); //リストのサイズを増加させない操作を設定し、要素の位置にある要素を設定して、追加の違いに注意を払います
public void add(int index, E element) {
//检查下标合法性
checkPositionIndex(index);
if (index == size)
//在尾部插入
linkLast(element);
else
//在指定位置插入
linkBefore(element, node(index));
}
リストの基本的な使用として、無膨張機構LinkedListのようにします。各後、LinkedListは以下の構造を追加します。
3.4操作を削除
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
//判断相等的标准也是两个对象通过equals方法比较相等
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
//清空链表
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
3.5クエリ操作
LinkedListのクエリ方法は、いくつかの一般的なクエリ方法があり、以下の(と同じでのArrayList)として要素を含めるかどうかを照会します。
- パブリックブール(オブジェクトo)が含まれています。
- 公共のintのindexOf(オブジェクトo);
- 公共int型のlastIndexOf。
- 公共Eは、(int型のインデックス)を取得します。
public boolean contains(Object o) {
return indexOf(o) != -1;
}
//判断的标准也是equals方法
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
3.6その他の方法
LinkedListのものDequeにこのインタフェースを実装しているため、このクラスは、他の多くの方法を含みます。これらのメソッドは、キューを紹介仕上げ。
3.7 LinkedListの概要
- 容量制限のない環状にLinkedListは二重にリンクされたリストに基づいて、
- いいえ拡張要素は、(直接、新しいノードを作成し、ポインタが挿入ノードの前と後のノードの特性を調整するために指すことができる)を添加していません。
- スレッドセーフ。
- (int型のインデックス)を取得:リストをトラバースする必要があります。
- 削除(オブジェクトo)リストをトラバースする必要があります。
- リストを横断する必要があります(int型のインデックス)を削除します。
- 含まれている(E)は、リストをトラバースする必要があります。
4.スレッドセーフリスト
ArrayListのとLinkedListのは、上記では、スレッドセーフなクラスを取得したい場合は、操作ワイヤの表面で包装することができる、スレッドセーフではありません。
List list = Collections.synchronizedList(new ArrayList(...));
リターンコードはSynchronizedListを超えています。ただ、スレッドセーフとしてこのクラスとベクトル。ベクターは、クラスjava.utilパッケージ、および静的な内部SynchronizedListのjava.util.Collectionsクラスです。両方のクラスは、リストのサブクラスであり、スレッドセーフです。どちらのクラスには、次のような違いがあります。
- 同期コードブロックは、ArrayListのメソッドをカプセル化除き、それらは、同期を達成する方法は、同期を達成するために使用されるベクターの同期方法、synchronizedList同期ブロックを使用する同期コードはありません。
- 2つの拡張機構は、2倍に同じ、ベクトル拡張が、元SynchronizedList 1.5倍に拡大されません。
- 優れた拡張と互換性のある機能を持っているSynchronizedList、彼はすべてのリストのサブクラスは、スレッドセーフなクラスに回すことができます。
- 故障のSynchronizedList方法は、()イテレータメソッド反復子を取得するために同期されて同期されていないので、手動で同期する横断する反復子を使用する場合(、又はループに使用次いでgetメソッドを呼び出します)。
これら2つのクラスがスレッドセーフであるが、ことに留意する必要があるが、我々は増加または反復での操作要素を減少させた場合、まだ高速失敗の例外が存在します。そのスレッドセーフかつ迅速な故障メカニズムは無関係である、高速故障メカニズムの目的は、反復要素のコースの要素の現在のセットを変更するために他のスレッドを防止することです。スレッドセーフなデータは、ダーティリードなどの問題を解決します。
5.なお、ポイント
配列は、ArrayListのある変換するには、開発者が頻繁に行います。
List<String> list = Arrays.asList(arr);
ArrayListのを取得することができますは、Arrays.asList()メソッドを使用しますが、実際のArrayList配列クラスで定義されているプライベート静的クラス内で取得します。このクラスと同じ名前のjava.util.ArrayListのではなく、同じクラスけれども。java.util.Arrays.ArrayListクラスはセットを()を実装し、(取得)、()メソッドなどが含まれていますが、定義する要素を追加する方法はありません。Arrays.asListのArrayListによって得られるサイズ()が固定されています。
開発中に、我々はオブジェクト(java.util.ArrayListののインスタンス)の本当のArrayListを取得したい場合は、以下の手段を通じて:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
java.util.ArrayList内には、コレクション型のコンストラクタは、パラメータを受け入れることができます含まれています。java.util.Arrays.ArrayListので、この内部クラスはAbstractListクラスを継承し、そのクラスには、コレクションのサブクラスです。
6.まとめ
究極の目標は、理解し、それを使用することができる何かを学ぶことです。まず、以下のとおり、さまざまな使用シナリオのリストについて説明します。「アレイ」に関連する変数の長さが最初の一覧を考慮しなければならない場合は、以下の基準に合わせてお選びどの特定のリストを選択します。
(01)素早く要素を削除、挿入する必要、あなたはLinkedListのを使用する必要があります。
(02)の要素への高速ランダムアクセスの必要性、あなたはArrayListのを使用する必要があります。
「シングルスレッド環境」又はために(03)、「マルチスレッド環境が、唯一つだけのスレッドリストの操作であろう」、この場合は(例えばArrayListのように)非同期であるべきです。「マルチスレッド環境、およびリスト同時に動作複数のスレッドであってもよい」は、この時間は、スレッドセーフなクラスは再利用としてパッケージ化ツールを使用して(ベクターなど)、同期またはコレクションのArrayListとLinkedListのによりすべきです。