初出 JAVA PRESS Vol.26

Java API ダイジェスト

java.util.List

ListインタフェースはJCFで策定されているインタフェースの中の1つです。JCFのインタフェースはすべてサイズが拡張可能で、どのようなオブジェクトでも保持することが可能です。しかし、プリミティブ型を直接保持できないので、Integerクラスなどのラッパクラスを使用するようにします。

ListインタフェースはCollectionインタフェースの派生インタフェースで、順序を持ったコレクションを表すために使用されます。

順序を持っているのでインデックスによるアクセスが可能ですが、キーによるアクセスはできません。また、重複した要素でも保持することが可能です。


インデックスアクセスへの対応

ListインタフェースのメソッドはCollectionインタフェースで定義されたものが多いのですが、インデックスアクセスに関するものはListインタフェースで定義されています。主なものとして要素に関するものと他のビューへの変換などがあります。

要素に関するメソッドには要素の取得、要素数の取得、要素の追加・挿入、削除などがあります。

■ コレクションの要素に関するメソッド

toArraysメソッドはListオブジェクトを配列に変換します。この他にも、Iteratorオブジェクトへの変換メソッドなども定義されています。

■ 他のビューへの変換

順序を持ったコレクション

■ コレクションの要素に関するメソッド

public Object get(int index)

リストのindex番目の要素を返します。リストに保持するのはObjectクラスなので、戻り値もObjectクラスです。このため、使用する時には適当な型にキャストする必要があります。

public int size()

リストの要素数を返します。このメソッドとgetメソッドを使用してシーケンシャルアクセスを行うことができます。リスト1はAクラスのオブジェクトを要素に持つリストからシーケンシャルに要素を取り出して、fooメソッドをコールする例です。

リスト 1 シーケンシャルアクセスの例
for(int i = 0 ; i < list.size() ; i++) {
    A a = (A)list.get(i);  // A へのキャストが必要
    a.foo();
}

public boolean add(Object obj)
public void add(int index, Object obj)

リストに要素の追加・挿入を行います。indexを指定した場合はindexの位置に挿入、なければリストの最後に追加されます。

public boolean remove(Object obj)
public Object remove(int index)

リスト内の要素の削除を行います。Objectが指定された場合、リスト内にある最初のobjと同じ要素が削除されます。このとき、同一オブジェクトでなくても、equalsメソッドでtrueになる要素であれば削除されます。

インデックスが指定されたときはindex番目の要素が削除されます。削除された要素以後の要素は 1 つづつ詰めて再配置されます。

addメソッドとremoveメソッドの使用例としてスタックとキューを紹介します。これらは要素の追加、取り出しだけを行えるコレクションです。2つの違いは要素を取り出す時に、スタックが最後に追加したものから順に取れるのに対して、キューが最初に登録した要素から順に取れるということです。

リスト2がスタック、リスト3がキューになります。双方とも、追加がpushメソッド、取り出しがpopメソッドです。スタックはリストの最後に追加、削除が行われるのでArrayListクラス、キューは取り出しに先頭要素を削除するためLinkedListクラスを使ってみました (コラム参照)。ちなみに、Stackクラスはjava.utilパッケージにありますが、Vectorの派生クラスであるため、ここではListを使用して作成してみました。

リスト 2 スタックの例
public class Stack {
    private List list;
    public Stack() {
        list = new ArrayList();
    }
    public void push(Object obj) {
        list.add(obj);
    }
    public Object pop() throws IndexOutOfBoundsException {
        int index = list.size() - 1;
        Object obj = list.get(index);
        list.remove(index);
        return obj;
    }
}

 

リスト 3 キューの例
public class Queue {
    private List list;
    public Queue() {
        list = new LinkedList();
    }
    public void push(Object obj) {
        list.add(obj);
    }
    public Object pop() throws IndexOutOfBoundsException {
        list.get(0);
        list.remove(0);
        return obj;
    }
}

■ 他のビューへの変換

public Object[] toArray()
public Object[] toArray(Object[] a)

Listオブジェクトを配列に変換します。引数の配列は Listオブジェクトの格納先を指定する場合に使用します。ただし、aのサイズが足りない場合、aと同一型の新しい配列を生成して使用します。

 

コラム ArrayListかLinkedListか

Listインタフェースを実装したクラスはArrayList、LinkedList、Vectorの3種類です。Java 2ではVectorを使う意味はほとんどないので、通常は残りの2つのクラスから選択します。

ArrayListクラスは配列でリストを実装しており、要素のアクセスは高速です。しかし、要素の挿入・削除は挿入・削除した位置以降の要素をすべてずらす必要があるため低速です。

LinkedListクラスはリスト構造を使用して実装しています。このため、要素のアクセスは参照をたどるため低速です。しかし、要素の挿入・削除は参照を付け替えるだけなので、非常に高速です。

これをまとめたのが表1です。2つのクラスの特徴を踏まえて、使用目的に応じたクラス選択がListインタフェースを使いこなすポイントとなります。通常は ArrayListクラスを使用し、要素数が多くて要素の挿入・削除を頻繁に行う場合にLinkedListクラスを使用すればいいと思います。

表1 ArrayListとLinkedListの比較

  インデキシング 要素の追加 要素の挿入 要素の削除
ArrayList × ×
LinkedList ×

 

ArrayListへの要素の挿入

図 1 ArrayListへの要素の挿入

LinkedListへの要素の挿入

図 2 LinkedListへの要素の挿入

(2002.09)