【java】ジェネリクスの実装方法をわかりやすく説明

java

クロネコ先生!
javaの勉強をしてるんですけど、ジェネリクスがまったくわからないです…

ジェネリクスですね!
これを理解できれば、かなり実務的なレベルの技術が身につくからしっかり教えていくよ!

ジェネリクスとは総称型と言われています。
この技術がなぜ必要かは実装をみると早いと思われます。

public class Main {
	public static void main(String[] args) {

		List list = new ArrayList();

		// String型とint型をリスト追加する
		list.add("a");
		list.add(1);

		Main2 main2 = new Main2();
		main2.exe(list);
	}
}
public class Main2 {
	public static void exe(List list) {

		// String型のみが引き渡されることを想定してしまっている
		// コンパイルエラーは出力されず、実行時にエラーが出力されてしまう
		for (Object o : list) {
			System.out.println((String) o);
		}
	}
}

Main2クラスでは、Mainクラスから引き渡されたlistをobject型からString型にキャストして出力する実装を行っています。
String型のみが引き渡されることを想定していますが、int型がlistに追加されていた場合は、コンパイルエラーは出力されず、実行時にはじめてエラーが出力されてしまいます。
このようなダウンキャストについては、実行してみないと見つけることができないエラーが発生することが多いです。
正しいコードは以下になります。

public class Main3 {
	public static void main(String[] args) {

		// ジェネリクスでString型を指定する
		List<String> list = new ArrayList();

		// int型をリスト追加しようとするとコンパイルエラーになる
		list.add("a");

		Main2 main2 = new Main2();
		main2.exe(list);
	}
}
public class Main4 {
	// ジェネリクスでString型を指定する
	public static void exe(List<String> list) {

		for (String s : list) {
			System.out.println(s);
		}
	}
}

Main4クラスにてジェネリクスでString型を指定し、引き渡されるlistの型に制限をかけることでエラーのすり抜けを防ぐことができます。
問題なのは、実行しないとエラーを検出できないということにあります。
あらかじめこういったエラーが発生しないようにするために実装するのがジェネリクスになります。
ジェネリクスによって「この型しか扱えません」という制限をかけておくことで予期せぬエラー発生を防ぐことができます。



実行しないとエラーを検出できないというのが問題なんですね!

その通りです!
ジェネリクスを使えば事前にエラーを防ぐことができますね!

業務で使うジェネリクスの実装

ここまではジェネリクスを使う上での前提知識をお伝えしました。
ここから実践的な実装方法について解説していきます。

public class Main5 {
	private Object o;

	public Object getObject() {
		return o;
	}

	public void setObject(Object o) {
		this.o = o;
	}
}

上記のMain5クラスのインスタンスを生成した場合は、メソッドを使用する際の型は、当然Object型になります。

public class Main6<T> {
	private T o;

	public T getObject() {
		return o;
	}

	public void setObject(T o) {
		this.o = o;
	}
}

上記のMain6クラスをインスタンス化し、メソッドを使用する場合は型を指定(Tが指定した型に置き換わる)することができます。
TはTypeの略です。好きな文字を使用していただいて構いません。

public class Main7 {
	public static void main(String[] args) {
		
		// <>に型を指定してインスタンス化する
		Main6<Integer> main6 = new Main6<>();
		main6.setObject(1);
	}
}

インスタンス化する際に、型を指定して生成することができるようになります。

Integer型だけでなく、String型、それ以外の型も指定できるからとっても便利ですね!

コメント

タイトルとURLをコピーしました