リスト

Listは,順序づけられた,連続したデータを格納するためのコレクションである.addメソッドを使って,データを順に追加していくことができる.

リスト構造を使うために用意されているものを確認する.Listをリファレンスで確認する.

Listはインタフェースである.

インタフェースList

Listインタフェースは,Collection<E>, Iterable<E >のサブ・インタフェースである.

Listインタフェースは次のように定義されている.

public interface List<E>
extends Collection<E>

さらに,Collectionインターフェースは次のように定義されている.

public interface Collection<E>
extends Iterable<E>

既知の実装されているクラスとしてArrayListクラスがある.では,実際インスタンスとして使うクラスをArrayListとしよう.ArrayListクラスを型としてもよいが,すでに上位のインタフェースで定義されているメソッドの範囲で十分であるので,List型にする.

このとき,<E>でリストで扱うデータの型を指定する.例えば,リストに格納するデータの型が文字列である場合は「String」クラスを<String>のように指定する.自分で定義したクラスでもよい.なお,Eはelementを意味する.

コレクションを使うときの特徴として,格納するデータの型を表すクラスを指定してインスタンス化することである.具体的には,「<>」で囲まれた部分であり,以下の場合には,Stringクラスのデータを格納することを意味している.このような「型」を指定して構成できるしくみをジェネリクス(Generics)と呼ぶ.これによって,リストに含まれるデータの型が一定になるため,持っているメソッドやフィールドが約束される.

Listインタフェースに定義されているメソッドを確認する.(参照:List (Java Platform SE 8)

修飾子と型メソッド説明
booleanadd(E e) 指定された要素をこのリストの最後に追加します(オプションの操作)。
E get(int index) このリスト内の指定された位置にある要素を返します。
int size() このリスト内にある要素の数を返します。

これを使って,リストデータ構造を利用する.

import java.util.ArrayList;
import java.util.List;
public class Main
{
    public static void main(String args[])
    {
        List<String>vegitableList = new ArrayList<String>();
        vegitableList.add("なす");
        vegitableList.add("きゅうり");
        vegitableList.add("とまと");
        for(int i=0;i<vegitableList.size();i++)
        {
            System.out.println(i + ":" +vegitableList.get(i));
        }
        vegitableList.set(1, "かぼちゃ");
        for(int i=0;i<vegitableList.size();i++)
        {
            System.out.println(i + ":" +vegitableList.get(i));
        }
    }
}
0:なす
1:きゅうり
2:とまと
0:なす
1:かぼちゃ
2:とまと

Listインターフェースには,ソートするメソッドが定義されている.sortメソッドを用いることで,簡単にソートすることができる.(参照:List (Java Platform SE 8)

修飾子と型メソッド説明
default voidsort(Comparator<? super E> c) 指定されたComparatorが示す順序に従って、このリストをソートします。

単純なデータ型である時には,ソートのルールを指摘せずとも,自然順序で並べ替えが行われる.まずは,何もルールを指定しない,「null」を渡して,ソートがなされることを確認する.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main
{
    public static void main(String args[])
    {
        List<String> vegitableList = new ArrayList<String>();
        vegitableList.add("なす");
        vegitableList.add("きゅうり");
        vegitableList.add("とまと");
        //追加した順に表示する
        for(int i=0;i<vegitableList.size();i++)
        {
            System.out.println(i + ":" +vegitableList.get(i));
        }
        //特定の順番のデータを変更する
        vegitableList.set(1, "かぼちゃ");
        for(int i=0;i<vegitableList.size();i++)
        {
            System.out.println(i + ":" +vegitableList.get(i));
        }
        //データをソートする
        vegitableList.sort(null);
        System.out.println(vegitableList);
    }
}
0:なす
1:きゅうり
2:とまと
0:なす
1:かぼちゃ
2:とまと
[かぼちゃ, とまと, なす]

格納するデータ型として,独自のクラスを設定することもできる.ここでは,YasaiクラスをListに格納される型として定義する.YasaiクラスのオブジェクトをvegitableListリストに順に格納している.

import java.util.ArrayList;
import java.util.List;
public class Main
{
    public static void main(String args[])
    {
        List<Yasai> vegitableList = new ArrayList<Yasai>();
        vegitableList.add(new Yasai("なす"));
        vegitableList.add(new Yasai("きゅうり"));
        vegitableList.add(new Yasai("とまと"));
        for(int i=0;i < vegitableList.size();i++)
        {
            System.out.println(i + ":" + vegitableList.get(i).getName());
        }
        vegitableList.set(1, new Yasai("かぼちゃ"));
        for(int i=0;i < vegitableList.size();i++)
        {
            System.out.println(i + ":" +vegitableList.get(i).getName());
        }
    }
}
class Yasai
{
    String name;
    Yasai(String name)
    {
        setName(name);
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
}
0:なす
1:きゅうり
2:とまと
0:なす
1:かぼちゃ
2:とまと

このとき,sortメソッドで,自然順序で並べ替えを行おうとしても(sort(nulll)),うまくいかない.これは,データがクラスで定義されていて複雑であるため,何を基準に並へ変えを行えばよいかわからないからである. そこで,並べ替えのルールを明確に決める.自然順序でない,独自のルールでソートすることもできる.

例えば,Yasaiクラスが,野菜名と,100gあたりのカロリーを持つとする.このとき,カロリーで並べ替えをしたいときには,カロリーの値で大小関係を定義してあげることで,並べ替えのルールを与えることができる.並べ替えのルールそのものも,オブジェクトであるため,クラスとして定義して,インスタンス化してsortメソッドに渡している.

sortのルールとしての役割を果たすためには,指定された要件を満たしている必要がある.その要件は,インターフェースとして指定されている.すなわち,指定されたインターフェースを実装することで,ソートに必要なルールセットを満たすことが約束される.ここでは,Comparatorインタフェースが指定されているので,それを実装することで,並べ替えのルールが完成する.

Comparatorインターフェースを実装したオブジェクトで並べ替えのルールを定義して,インスタンスを渡すことで,指定した並べ替えを行うことができる. Comparatorインターフェースを見る.compareメソッドを実装する必要がありそうである.その仕様は以下のようになっている.

compare
順序付けのために2つの引数を比較します。最初の引数が2番目の引数より小さい場合は負の整数、両方が等しい場合は0、最初の引数が2番目の引数より大きい場合は正の整数を返します。 前述の説明では、sgn(expression)という表記は数学関数signumを示し、expressionの値(負の数、ゼロ、正の数)に応じて、-1、0、1のどれかを返します。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public class Main
{
    public static void main(String args[])
    {
        List<Yasai> vegitableList = new ArrayList<Yasai>();
        vegitableList.add(new Yasai("なす",22));
        vegitableList.add(new Yasai("きゅうり",14));
        vegitableList.add(new Yasai("とまと",19));
        vegitableList.add(new Yasai("かぼちゃ",93));
        for(int i=0;i<vegitableList.size();i++)
        {
            System.out.println(i + ":" + vegitableList.get(i).getName() + ":" +                                     
            vegitableList.get(i).getCalorie());
        }
        vegitableList.sort(new CalorieComparetor());
        for(int i=0;i<vegitableList.size();i++)
        {
            System.out.println(i + ":" + vegitableList.get(i).getName() + ":" +                                     
            vegitableList.get(i).getCalorie());
        }
    }
}
class Yasai
{
    String name;
    int calorie;
    Yasai(String name, int calorie)
    {
        setName(name);
        setCalorie(calorie);
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getCalorie()
    {
        return calorie;
    }
    public void setCalorie(int calorie)
    {
        this.calorie = calorie;
    }
}
class CalorieComparator implements Comparator<Yasai>
{
    public int compare(Yasai yasai1, Yasai yasai2)
    {
        int calorie1 = yasai1.getCalorie();
        int calorie2 = yasai2.getCalorie();
        if(calorie1 > calorie2)
        {
            return 1;
        }
        else if(calorie1 == calorie2)
        {
            return 0;
        }
        else //(calorie1 < calorie2)
        {
            return -1;
        }
    }
}
0:なす:22
1:きゅうり:14
2:とまと:19
3:かぼちゃ:93
きゅうり:14
とまと:19
なす:22
かぼちゃ:93

ジェネリクス補足

List<Number> numberList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();

//Numberクラスを継承したクラスの型である仮宣言 List<? extends Number> wildNumberExtendsList = new ArrayList<>(); wildNumberExtendsList = numberList; //OK:NumberクラスはNumberも含むので許容される wildNumberExtendsList = integerList; //OK:IntegerクラスはNumberクラスを継承しているので許容される
//Integerクラスを継承したクラスの型である仮宣言 List<? extends Integer> wildExtendsIntegerList = new ArrayList<>(); wildExtendsIntegerList = integerList; //OK:IntegerクラスはNumberクラスを継承しているので許容される //wildExtendsIntegerList = numberList; //NG:NumberクラスはIntegerクラスのスーパークラスなので許容されない
//Integerクラスをサブクラスに持つスーパークラスの型になる仮宣言 List<? super Integer> wildSuperIntegerList = new ArrayList<>(); wildSuperIntegerList = integerList;//OK:IntegerはIntegerクラスも含むので許容される wildSuperIntegerList = numberList;//OK:NumberクラスはIntegerクラスのスーパークラスなので許容される
//Numberクラスをサブクラスに持つスーパークラスの型になる仮宣言 List<? super Number> wildSuperNumberList = new ArrayList<>(); //wildSuperNumberList = integerList;//NG:IntegerクラスはNumberのスーパークラスではないので許容されない wildSuperNumberList = numberList;//OK:NumberクラスはNumberクラスそのものなので許容される