【Java】可変長配列、List系クラス

2018年7月26日

本稿は、可変長配列であるArrayList、LinkedListについて説明します。

可変長配列は、通常の配列とは違い、データを保持できるサイズを考えずに要素を追加できます。

ゲーム制作では、ゲーム内のオブジェクトを保持したい時に重宝します。

ゲーム制作以外でも良く使用されるので、せめてArrayListだけでも使用できるようにしておきましょう。

ArrayListクラス

ArayListは内部で普通の配列を保持し、サイズが足りなくなると自動で拡張してくれる便利なJavaクラスです。java.utilパッケージからインポートして使用してください。

ArrayListは使用したい型を<>で囲み、囲んだ要素を可変長配列として扱えるようになります。

<>はなくてもキャストすれば使用できるのですが、この方法は古いので、<>で囲んで使用する方法を使っていきましょう。

ArrayListのインスタンス化はArrayList<参照型> 変数名 = new ArrayList<>();で可能です。

基本型を指定したい場合はラッパークラスを使用します。

それでは、実際にint型の可変長配列をインスタンス化してみましょう。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
	}
}

intのラッパークラスはIntegerなのでArrayList<Integer>と指定すればOK

addメソッド

ArrayListに要素を追加する場合はaddメソッドを利用します。

addメソッドは、配列の最後にデータを追加します。

サイズは気にせず、追加していけます。

試しに、何個か数値を追加してみましょう。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		System.out.println(arr);
	}
}
実行結果

[300, 54, 22]

追加した順に表示されていますね。


追加するデータの位置ですが最後ではなく、要素の途中に挿入することもできます。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(300);
		arr.add(54);
		arr.add(1,22);//1番に22を挿入
		System.out.println(arr);
	}
}
実行結果

[300, 22, 54]

要素を配列の末尾以外に挿入すると、挿入位置以降の要素が順番に後ろにずれていきます。

ずらす処理が入る分処理が重くなりますので基本的に最後に挿入するほうが良いでしょう。

getメソッド

ArrayListから要素を取得する場合はgetメソッドを利用します。

試しに、追加したデータを取り出してみましょう。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		System.out.println(arr.get(1));
	}
}
実行結果

54

この例では2番目のデータを取り出しました。

配列と同じように、要素番号は0から始まるので注意してください。

存在しない番号にアクセスすると、IndexOutOfBoundsExceptionが発生します。

removeメソッド

ArrayListから要素を削除する場合はremoveメソッドを利用します。

試しに、追加したデータを削除してみましょう。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		arr.remove(1);
		System.out.println(arr);
	}
}
実行結果

[300, 22]

2番目に挿入された、データである54を削除したので結果に54は含まれなくなりましたね。

removeメソッドで要素が削除されると削除された位置以降のデータは前へ詰められます。

詰める処理が走る分処理が重くなってしまいます。

後ろの要素ほど詰める処理が少なくなるので、速度は早くなります。

ArrayList内部のデータを削除する時は、なるべく要素の後ろから削除するように心がけましょう。

sizeメソッド

現在の要素数を取得します。普通の配列のlengthに当たるメソッドです。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		System.out.println(arr.size());
	}
}
実行結果

3

全ての要素にアクセス

ArrayListクラスはIterableインターフェースを実装しているのですが、このインターフェースを実装したクラスは拡張for文で使用できます。

実際に拡張for文で要素を改行区切りで表示してみましょう。

import java.util.ArrayList;

public class Test{
	public static void main(String[] args){
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		for (int data : arr) {
			System.out.println(data);
		}
	}
}
実行結果

300
54
22

もちろんsizeメソッドやgetメソッドを利用する方法でも全要素へのアクセスは可能です。

LinkedListクラス

LinkedListクラスはArrayListと同じように使用できるのですが、内部の処理が異なっており、データに次と前への参照を持たせて、保持する形式となっています。

要素へのアクセスは、次の参照を辿っていき、行います。

難しいかもしれないので、中身の構造まで理解しなくても構いません。どういう時に処理速度が速くなるか、遅くなるかなどだけ知っておけば良いです。

addメソッドは高速ですがgetメソッド、removeメソッドのような番号を指定したメソッドは、最初の要素から順番にアクセスし、目的の番号まで辿り着かなければならないため、処理速度が遅くなります。

そのかわり、要素の最初と最後へアクセスする場合は高速に動作します。

LinkedListもjava.utilパッケージに含まれるので、インポートしておきましょう。

LinkedListのインスタンス化はLinkedList<参照型> 変数名 = new LinkedList<>();で可能です。

int配列を作成するサンプルです。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
	}
}

ArrayListとそう変わりはありませんので問題ないと思います。

addFirst、addLastメソッド

addFirstメソッドはリストの先頭にデータを追加できます。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.addFirst(300);
		arr.addFirst(54);
		arr.addFirst(22);
		System.out.println(arr);
	}
}
実行結果

[22, 54, 300]

要素の最初に追加したので、一番最後に追加した22が先頭の要素となりました。


addLastメソッドはリストの最後にデータを追加できます。addメソッドでも同じ処理ができます。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.addLast(300);
		arr.addLast(54);
		arr.addLast(22);
		System.out.println(arr);
	}
}
実行結果

[300, 54, 22]

getFirst、getLastメソッド

getFirstメソッドはリストの先頭のデータを取得できます。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.addLast(300);
		arr.addLast(54);
		arr.addLast(22);
		System.out.println(arr.getFirst());
	}
}
実行結果

300


getLastメソッドはリストの最後のデータを取得できます。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.addLast(300);
		arr.addLast(54);
		arr.addLast(22);
		System.out.println(arr.getLast());
	}
}
実行結果

22

removeFirst、removeLastメソッド

removeFirstメソッドはリストの先頭のデータを削除できます。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.addLast(300);
		arr.addLast(54);
		arr.addLast(22);
		arr.removeFirst();
		System.out.println(arr);
	}
}
実行結果

[54, 22]

最初の要素である300が削除されました。


removeLastメソッドはリストの最後のデータを削除できます。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.addLast(300);
		arr.addLast(54);
		arr.addLast(22);
		arr.removeLast();
		System.out.println(arr);
	}
}
実行結果

[300, 54]

最後の要素である22が削除されました。

sizeメソッド

現在の要素数を取得します。

import java.util.LinkedList;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		System.out.println(arr.size());
	}
}
実行結果

3

Iteratorで全要素アクセス

LinkedListクラスもIterableインターフェースを実装しているため、拡張for文で使用できます。

LinkedListはgetメソッドが遅いので通常の方法での順次アクセスはかなり遅くなるのですが、拡張for文で利用すると通常の順次アクセスより処理速度が上がります。

また、Iteratorを利用して、アクセスすれば、最初や最後以外の要素の削除も通常の順次アクセスより高速に行えます。

ここではIteratorオブジェクトを利用したアクセスと削除を実行するサンプルを紹介します。

import java.util.LinkedList;

//Iteratorもインポートしてください
import java.util.Iterator;

public class Test{
	public static void main(String[] args){
		LinkedList<Integer> arr = new LinkedList<>();
		arr.add(300);
		arr.add(54);
		arr.add(22);
		
		//Iteratorオブジェクトの取得
		Iterator<Integer> it = arr.iterator();
		
		//hasNextは次の要素が存在するかを判定できます。
		while ( it.hasNext() ) {
			int data = it.next();//次の要素を取得します。
			
			//数値が54なら削除を実行します。
			if ( data == 54 ) {
				it.remove();
			}
		}
		
		System.out.println(arr);
	}
}
実行結果

[300, 22]

54が削除されました。

※2018/07/26、最後のサンプルプログラムのIteratorのカッコ抜けを修正させていただきました。ご指摘いただいた方、ありがとうございました。

Java

Posted by nompor