2.9. java.util.ArrayList。配列をすごく便利にします。¶
ArrayListは配列を使いやすく拡張したクラスです。
配列はそのままでは扱いにくいので、ArrayListを使いましょう。
削除や挿入など、配列を操作する機能が盛りだくさんで、とても便利です。
※ArrayListは結構機能が多くて、ドキュメントが大きくなりました。
2.9.1. クラス図へ変換¶
では、早速クラス図にしてみます。
UML変換くんを実行。
> touml .\java\util\ArrayList.java
> touml .\java\util\AbstarctList.java
> touml .\java\util\AbstractCollection.java
※java1.8コード
ArrayListだけではなく、親クラスと、親の親クラスもクラス図にしました。
※こうしないと、全体がみえくかったです。
2.9.1.2. クラス図¶
クラスです。java.util.ArrayList
親クラスです。java.util.AbstractList
親の親クラスです。 java.util.AbstractCollection
元の図は大きいので小さく切り取って、見ていきます。
2.9.2. 継承¶
2.9.2.1. ArrayList。ターゲットのクラス。¶
2.9.2.1.1. AbstarctListを継承しています。¶
ですので、このクラスの処理を流用して処理を共通化する設計になっています。
2.9.2.1.2. RandomAccessを実現しています。¶
ランダムアクセスできるよ、という目印になります。
配列のように添え字(例a[1]、a[2])で直接データにアクセスできるようなものをいいます。
※そうじゃないものもあります、例えば前から順番にしかアクセスできないとか。
2.9.2.1.3. Listを実現しています。¶
ListはList関連のクラスの共通インタフェースになっています。
2.9.2.1.4. Serializableを実現しています。¶
これを実現するとシリアライズできるよと、という意味になります。
2.9.2.2. 親クラスのAbstractList¶
2.9.2.2.1. まずはListを実現しています。¶
List関連のクラスはこれを実現することになっています。
2.9.2.2.2. AbstractCollectionを継承しています。¶
Collectionというのは、Listよりももっと幅の広い概念で、集めたもの集合のような意味になります。
なので、この意味に共通する処理を共有しています。つまりAbstractCollectionの処理を流用しています。
2.9.2.3. 親の親クラスAbstractCollection¶
2.9.2.3.1. Collectionを実現していますね。¶
Collection関連クラスはこのインタフェースを実現することになっています。
2.9.3. フィールドを見てみる¶
2.9.3.1. ArrayList。ターゲットのクラス¶
2.9.3.1.1. serialVersionUID¶
-serialVersionUID:long=8683452581122892189L{readOnly}
シリアライズ用のIDでシリアライズするときに必要なものです。
2.9.3.1.2. DEFAULT_CAPACITY¶
-DEFAULT_CAPACITY:int=10{readOnly}
デファオルトで確保する配列サイズです。このサイズで領域を増やしていきます。
2.9.3.1.3. EMPTY_ELEMENTDATA¶
-EMPTY_ELEMENTDATA:Object[]={}{readOnly}
サイズを0で指定してインスタンスを生成した時は配列にこれが使われます。
2.9.3.1.4. DEFAULTCAPACITY_EMPTY_ELEMENTDATA¶
-DEFAULTCAPACITY_EMPTY_ELEMENTDATA:Object[]={}{readOnly}
サイズを指定しないでインスタンスを生成した時などにこの配列がセットされます。
2.9.3.1.7. MAX_ARRAY_SIZE¶
-MAX_ARRAY_SIZE:int=Integer.MAX_VALUE-8{readOnly}
ArrayListに格納できる配列の最大サイズです。
2.9.3.2. 親クラスのAbstractList¶
2.9.3.2.1. modCount¶
#modCount:int=0{transient}
modification Countの略で、削除とか挿入とかを行うたびにmodCountをカウントアップした値をセットしていました。
これは何に使っているんだろうと、調べてみました。
元のリストから部分リストを取得したり、Iteratorを取得して操作するときに使っていました。
元のリストのmodCountと違いが無いかチェックして違うと例外を発生させます。
つまり、元リストと部分リストなどとの整合性が取れなくなっていないかをチェックするためのモノのようでした。
2.9.3.3. 親の親クラスAbstractCollection¶
2.9.3.3.1. MAX_ARRAY_SIZE¶
-MAX_ARRAY_SIZE:int=Integer.MAX_VALUE-8{readOnly}
AbstractCollectionに格納できる配列の最大数。
2.9.4. メソッドを眺めてみます¶
2.9.4.1. ArrayList。ターゲットのクラス¶
2.9.4.1.1. コンストラクタ¶
+ArrayList(initialCapacity:int):void
+ArrayList():void
+ArrayList(c:Collection<?extends E>):void
この辺はコンストラクタです。
引数がCollectionのモノは中で配列を生成しいてコピーしています。
2.9.4.1.2. trimToSize¶
+trimToSize():void
格納されているサイズに合わせて、キャパシティを刈り込んで(trim)いました。
メモリーの有効活用ということでしょう。
※Arrays.copyOfを使ってtrimしています。
2.9.4.1.3. ensureCapacity¶
+ensureCapacity(minCapacity:int):void
-ensureCapacityInternal(minCapacity:int):void
-ensureExplicitCapacity(minCapacity:int):void
-grow(minCapacity:int):void
-hugeCapacity(minCapacity:int):int
引数の数値をもとに、キャパシティを確保(ensure)する処理です。
※あらかじめキャパシティを大きくとっておきたいときに使うのでしょう。
2.9.4.1.4. size¶
+size():int
+isEmpty():boolean
+contains(o:Object):boolean
格納している要素の数を取得する関連。
containsは引数のモノが含まれているか確認する機能です。
2.9.4.1.5. indexOf¶
+indexOf(o:Object):int
+lastIndexOf(o:Object):in
indexOfは配列の先頭から検索して、その位置を返す。
lastIndexOfは配列の後ろから検索して、その位置を返す。
2.9.4.1.11. remove¶
+remove(index:int):E
+remove(o:Object):boolean
-fastRemove(index:int):void
+clear():void
removeは引数で指定した位置やモノを削除します。
fastRemoveはremoveの中で使われています。
配列コピーのSystem.arraycopyを使って実装しています。fastとついているので高速なのでしょうか。
clearは配列をサイズ分forループで回してnullで埋めます。
2.9.4.1.12. addAll¶
+addAll(c:Collection<?extends E>):boolean
+addAll(index:int,c:Collection<?extends E>):boolean
Collection集合をまとめて、追加することができます。 配列コピーのSystem.arraycopyを使っています。
2.9.4.1.13. removeRange¶
#removeRange(fromIndex:int,toIndex:int):void
-rangeCheck(index:int):void
-rangeCheckForAdd(index:int):void
-outOfBoundsMsg(index:int):String
+removeAll(c:Collection<?>):boolean
removeRangeは指定された範囲の内部配列を削除します。
rangeCheckは引数indexが範囲内かチェックをします。範囲外ならIndexOutOfBoundsException例外発生。
outOfBoundsMsgはrangeCheckの中で使われていて、例外メッセージ文字列を作っています。
2.9.4.1.14. retainAll¶
+retainAll(c:Collection<?>):boolean
-batchRemove(c:Collection<?>,complement:boolean):boolean
retainAllは引数の集合のものだけは保持(retain)して、それ以外は削除します。
batchRemoveはretainAllの中で使われています。
2.9.4.1.15. writeObject¶
-writeObject(s:java.io.ObjectOutputStream):void
-readObject(s:java.io.ObjectInputStream):void
これは、シリアライズに使う処理です。
引数Streamに内部配列を書き込んだり、読み込んだりします。
2.9.4.1.16. iterator¶
+listIterator(index:int):ListIterator<E>
+listIterator():ListIterator<E>
+iterator():Iterator<E>
イテレーターとして、内部配列を取得します。
イテレーターの種類によって、アクセスだけできるとか、編集できるとか違いはあります。
処理は内部クラスのListItr、Itrで行っています。
2.9.4.1.17. subList¶
+subList(fromIndex:int,toIndex:int):List<E>
~subListRangeCheck(fromIndex:int,toIndex:int,size:int):void
指定した範囲の一部分(sub)のListを返却します。
全体ではなく部分だけ欲しいときに使います。
処理は内部クラスのSubListで行っています。
2.9.4.1.18. forEach¶
+forEach(action:Consumer<?super E>):void
戻り値のない関数型インタフェースを引数にセットすると、for eachのようにforループを実行する。
つまりはfor構文ではなく、メソッドでfor eachを再現したものです。
※Consumerのvoid accept(T t)をオーバーライドします。
2.9.4.1.19. spliterator¶
+spliterator():Spliterator<E>
イテレーターの一種である、スプリッテレーターを返します。
trySplit()メソッドと使うとListを簡単に分割することができて、並列処理に便利なようです。
※これは使ったことが無いので、いまいち用途が分かりにくいのですが...。
2.9.4.1.20. removeIf¶
+removeIf(filter:Predicate<?super E>):boolean
引数filterにセットした関数クラスの条件に合った要素を削除します。
※Predicateのboolean test(T t)をオーバーライドします。
2.9.4.1.21. replaceAll¶
+replaceAll(operator:UnaryOperator<E>):void
引数operatorにセットした関数クラスの処理により、要素の内容を置き換えます。
※UnaryOperatorの親クラスのFunction のR apply(T t);をオーバーライドします。
2.9.4.1.22. sort¶
+sort(c:Comparator<?super E>):void
引数cにセットした関数クラスの比較処理により、要素の並べ替えをします。
※Comparatorのint compare(T o1, T o2)をオーバーライドします。
2.9.4.2. 親クラスのAbstractList¶
2.9.4.2.2. add¶
+add(e:E):boolean
「+add(index:int,element:E):void」を中で読んでいるだけです。 ※add(size(), e); 配列の末尾に引数eを追加します。
2.9.4.2.3. get、set¶
+get(index:int):E
+set(index:int,element:E):E
引数indexの位置の要素を取得したり、設定したりします。
※ただ、このメソッドはオーバーライドして使われることを想定しているようです。
※呼ぶとUnsupportedOperationExceptionの例外が発生します。
2.9.4.2.4. add¶
+add(index:int,element:E):void
引数indexの位置に要素を挿入します。
※ただ、このメソッドはオーバーライドして使われることを想定しているようです。
※呼ぶとUnsupportedOperationExceptionの例外が発生します。
2.9.4.2.5. remove¶
+remove(index:int):E
引数indexの位置に要素を削除します。
※ただ、このメソッドはオーバーライドして使われることを想定しているようです。
※呼ぶとUnsupportedOperationExceptionの例外が発生します。
2.9.4.2.6. indexOf¶
+indexOf(o:Object):int
+lastIndexOf(o:Object):int
前方検索・後方検索検索して引数oがあったら、その位置を返します。
2.9.4.2.7. clear¶
+clear():void
配列要素をすべて削除します。
「#removeRange(fromIndex:int,toIndex:int):void」を読んでいるだけです。
※removeRange(0, size());
2.9.4.2.8. addAll¶
+addAll(index:int,c:Collection<?extends E>):boolean
index位置に引数cのCollection集合を挿入します。
「+add(index:int,element:E):void」を使って実装しています。
2.9.4.2.9. iterator¶
+iterator():Iterator<E>
+listIterator():ListIterator<E>
+listIterator(index:int{readOnly}):ListIterator<E>
内部クラスのItr、ListItrを生成して返却しています。
※上からこんな感じです。
「return new Itr();」
「return listIterator(0);」
「return new ListItr(index);」
2.9.4.2.10. subList¶
+subList(fromIndex:int,toIndex:int):List<E>
配列位置がfromIndexからtoIndexの範囲の部分リスト返します。
返すクラスは子クラスのRandomAccessSubListまたはSubListとなっています。
RandomAccessを実現しているどうかで処理を分けています。
2.9.4.2.14. rangeCheckForAdd¶
-rangeCheckForAdd(index:int):void
-outOfBoundsMsg(index:int):String
indexがListの範囲内にあるかチェックします。
また、indexが範囲外あるときのメッセージ文字列を作成します。
2.9.4.3. 親の親クラスAbstractCollection¶
2.9.4.3.3. size¶
+size():int
+isEmpty():boolean
サイズ(配列の要素数)を取得したりします。
sizeはオーバーライドしなければいけません。
isEmptyはsize()をコールして0だったらtrueを返しているだけです。
2.9.4.3.5. toArray¶
+toArray():Object[]
<T>+toArray(a:T[]):T[]
<T>-finishToArray(r:T[],it:Iterator<?>):T[]
-hugeCapacity(minCapacity:int):int
toArray内部配列の要素をコピーして返却する処理です。
つまり、Collectionから配列に変換しています。
引数a:T[]はサイズが足りていれば、これに配列コピーして戻り値として返します。
足りないときにはjava.lang.reflect.Array.newInstanceで新規に作った配列にコピーして返します。
2.9.4.3.6. add¶
+add(e:E):boolean
これは、常に例外UnsupportedOperationExceptionを投げます。
自分でオーバーライドしろということでしょう。
2.9.4.3.11. retainAll¶
+retainAll(c:Collection<?>):boolean
ちょうど、removeAllと逆の仕様になっています。
引数cの集合を内部配列に確保(retain)し、それ以外はすべて削除しています。
2.9.5. 内部クラス¶
2.9.5.1. Itr。イテレーターを作ります。¶
ArrayListクラスのメソッド「+iterator():Iterator<E>」内で生成して返されます。
※return new Itr();
ArrayListのイテレーター処理に使われます。
2.9.5.2. ListItr。Listイテレーターを作ります。¶
メソッド「+listIterator(index:int):ListIterator<E>」と、「+listIterator():ListIterator<E>」で生成されて返却されます。
ArrayListのListイテレーター処理に使われます。
※編集できるイテレーターです。
2.9.5.3. SubList。部分リストを作ります。¶
ArrayListから一部を切り出すために作られたクラスです。
ArrayListのメソッド「+subList(fromIndex:int,toIndex:int):List<E>」の中で生成されて返却されています。
※return new SubList(this, 0, fromIndex, toIndex);
2.9.5.4. ArrayListSpliterator。スプリッテレーターを作ります。¶
ArayListのイテレーターの一種である、スプリテレーターの処理をするために作られたクラスです。
ArrayListの「+spliterator():Spliterator<E>」メソッドで生成されて返却されます。
※return new ArrayListSpliterator<E>(ArrayList.this, offset, offset + this.size, this.modCount);
2.9.6. まとめ¶
ArrayListは配列を便利に利用できるようにしたクラスです。
これだけの機能がついて、かなり使いでのあるクラスになっています。
コードを調査していて思ったのが、これ内部クラスの使い方がうまいとなあと感じます。
クラス内の処理が複雑になってきた、内部クラスに処理を切り分けるときれいにまとめられるんですね。