「パラメトリック多相」はメソッドやクラスを定義する時に特定のデータ型に依存しないで総称的に記述出来るという性質のことで、Javaでは「ジェネリクス」機能により実現されます。
「パラメトリック多相」は「パラメータ多相」と呼ばれることもあります。
また「ジェネリクス」は「ジェネリック」「総称」「テンプレート」と呼ばれることもあります。
さてジェネリクスを使うと、引数やフィールドの型が違うだけでほとんど同じ内容のメソッドやクラスを何度も書く必要がなくなるので、ソースコードがスッキリしてバグの混入を防げます。
はじめに、メソッドにジェネリクスを適用する方法について説明します。
ジェネリクスを適用したメソッドのことを「ジェネリクスメソッド」とか「ジェネリックメソッド」とか「総称型メソッド」などと言います。
それではソース 1 を見て下さい。
ソース 1では String 型と Integer 型を引数として持つ show メソッドをオーバーロードして作っています。
public class Main{ public static void show( String a ){ System.out.println( a ); } public static void show( Integer a ){ System.out.println( a ); } public static void main(String[] args) { show("hoge"); show(123); } } 出力結果: hoge 123
ところが show メソッドは引数の型が違うだけで中身は同じなので2回書くのは無駄な気がします。
そこで以下の様に show メソッドをジェネリクスメソッドに書き換えます。
public class Main{ public static <T> void show( T a ){ System.out.println( a ); } public static void main(String[] args) { show("hoge"); show(123); } } 出力結果: hoge 123
すると show メソッドは1つしか定義してないのに全く同じ出力結果が得られました。
では詳しく説明します。
ソース 2 の show メソッドで、戻り値(void)の前にある <T> を「型パラメータ」や「仮パラメータ」や「仮型パラメータ」などと呼び、型パラメータが指定されているメソッドをジェネリクスメソッドと言います。
型パラメータを指定すると特定の型の代わりに型パラメータを型名として使えるようになります。
例えばソース 2 では T が型パラメータとなっています。
※ 型パラメータの文字は適当で結構ですが T (Typeの略) や E (Elementの略) とする事が多いです
ところでソース 2 の main メソッドにある show("hoge") と show(123) が ソース1と変わってないことに注目してください。
大抵のオブジェクト指向プログラミング言語ではジェクリクスメソッドを呼び出す時に型を自動認識してくれるので、呼び出し時にわざわざ引数の実際の型を指定する必要はありません。
次に、クラスにジェネリクスを適用した「ジェネリクスクラス」(または「ジェネリッククラス」、「総称型クラス」)について説明します。
※ 今まで特に説明しないで使ってきたリストも実はジェネリクスクラスの一つです。
それではソース 3〜5 を見て下さい。
この例では String 型及び Integer 型の data をフィールドとして持つ Hoge クラスと Fuga クラスを作っています。
public class Hoge{ private String data; public Hoge(String a){ data = a; } public String get_data(){ return data; } }
public class Fuga{ private Integer data; public Fuga(Integer a){ data = a; } public Integer get_data(){ return data; } }
public class Main{ public static void main(String[] args) { Hoge hoge = new Hoge("hoge"); Fuga fuga = new Fuga(123); System.out.println(hoge.get_data()); System.out.println(fuga.get_data()); } } 出力結果: hoge 123
ただし、見て分かるように中身は殆ど同じなので、Hoge クラスと Fuga クラスをジェネリクスクラス Piyo で統一してみましょう(ソース6)。
この様にジェネリクスクラスでは型パラメータはクラス名の後で指定します。
public class Piyo<T>{ private T data; public Piyo(T _data){ data = _data; } public T get_data(){ return data; } }
この Piyo クラスを使いたい時は次のソース 7 の様にします。
なおジェネリクスメソッドの時と違ってインスタンスを作る際に型を指定する必要があります。
※ プログラミング言語によっては型を自動認識するものもあります
public class Main{ public static void main(String[] args) { Piyo<String> hoge = new Piyo<String>("hoge"); Piyo<Integer> fuga = new Piyo<Integer>(123); System.out.println(hoge.get_data()); System.out.println(fuga.get_data()); } } 出力結果: hoge 123