Going my way

いいなと思ったことをメモしていきます。

なぜArrayListの参照変数はList型で宣言しなければならないのか


Advertisements


掲題の疑問について考えてみよう。
ついでに一度リストについてまとめる。

package sample2;

import java.util.ArrayList;
import java.util.List;

public class ListSample {
	public static void main(String[] args){
		
		//①
		ArrayList<String> list = new ArrayList<String>();
		List<Integer> list2 = new ArrayList<Integer>();
		
		//②コンパイルエラー
		//List<int> list3 = new ArrayList<int>();
		
		for(int i = 0; i < 10; i++){
			list2.add(i);
		}
		//list2:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		System.out.println("list2:"+list2);
		
		//size():10 サイズ
		System.out.println("size():"+list2.size());
		
		//get():3 要素取得
		System.out.println("get():"+list2.get(3));
		
		//contains():true 含まれているか
		System.out.println("contains():"+list2.contains(5));
	}
}

②コレクションの要素は参照型しか指定できない。基本型だとコンパイルエラーになる


①について

ArrayList<String> list = new ArrayList<String>
List<String> list = new ArrayList<String>

この2つの参照変数の宣言の違いは何か。

それは、Listがインタフェース型でArrayListが具象クラスである。

一般的に下の
List list = new ArrayList
が望ましいとされる。

理由は、インターフェースは変更されにくいものだからだ。
具象クラスは実装を持つため変化しやすい。
ソースコードは変更の影響を受けにくいものが望ましい。

もっとわかりやすい例で見てみよう。

package sample2;

public interface Oya {
	void sayHello();
	void sayGoodBye();
}

このインターフェースを継承する子クラス

package sample2;

public class Ko implements Oya{

	private Ko(){}
	@Override
	public void sayHello() {
		// TODO 自動生成されたメソッド・スタブ
		System.out.println("Hello!");
	}

	@Override
	public void sayGoodBye() {
		// TODO 自動生成されたメソッド・スタブ
		System.out.println("GoodBye!");
	}
	
	//ファクトリメソッド風に
	static Ko getInstance(){
		Ko ko = new Ko();
		return ko;
	}

}


さて、以下のコードを実行した結果はどうなるだろうか?

package sample2;

public class Main2 {
	public static void main(String[] args){
		//インターフェース型として宣言している。
		Oya ko = Ko.getInstance();
		ko.sayHello();
		ko.sayGoodBye();
	}
}


結果

Hello!
GoodBye!

インターフェース型として宣言すれば、具象クラスの振る舞いを利用しつつも、
変更に影響を受けにくいコードを書くことができるのである。