前回はテキストファイルの読み書きを学び、データを永続的に保存できるようになりました。 今回は「ジェネリクス(Generics)」について解説します。 ArrayListを使ったときに登場した <String> や <Integer> という書き方がジェネリクスです。その仕組みを理解することで、より安全で再利用しやすいコードが書けるようになります。
ジェネリクスの基本
これまで ArrayList<String> や ArrayList<Integer> のように、<> の中にデータ型を指定してきました。この <> の仕組みがジェネリクスです。
ジェネリクスを使わない場合、たとえば「何でも入れられる箱クラス」を作ろうとすると、取り出すたびにキャスト(型変換)が必要になり、型を間違えると実行時にエラーが起きてしまいます。
// ジェネリクスなしの場合
Object box = "こんにちは";
String value = (String) box; // キャストが必要
ジェネリクスを使うと、クラスを定義するときに型をあとから決めることができ、コンパイル時に型の間違いを検出できるようになります。
クラス名<型パラメータ>
慣習として、型パラメータには T(Type)、E(Element)、K(Key)、V(Value)などのアルファベット1文字がよく使われます。
サンプルコード(ジェネリクスを使ったクラス)
ファイル作成
「Java06」フォルダに Box.java、GenericsTest.java という名前でファイルを作成します

コード入力
Box.java に以下のコードを入力します。
public class Box<T> {
private T content;
void put(T item) {
content = item;
System.out.println("箱に入れました:" + item);
}
T get() {
return content;
}
}

GenericsTest.java に以下のコードを入力します。
public class GenericsTest {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.put("こんにちは");
String message = stringBox.get();
System.out.println("取り出した値:" + message);
Box<Integer> intBox = new Box<>();
intBox.put(100);
int number = intBox.get();
System.out.println("取り出した値:" + number);
}
}

コンパイル
javac Box.java GenericsTest.java

実行
java GenericsTest
実行結果は次のようになります。
箱に入れました:こんにちは
取り出した値:こんにちは
箱に入れました:100
取り出した値:100

コードの解説
Box<T> の T は「型パラメータ」と呼ばれ、インスタンスを作る際に実際の型を指定することで、その型に合わせたクラスとして動作します。Box<String> とすれば T がすべて String に、Box<Integer> とすれば T がすべて Integer に置き換わって動作するイメージです。
private T content; はフィールドで、put(T item) で値を受け取って保存し、get() で取り出します。Box<String> のインスタンスに対して stringBox.get() を呼ぶと、キャストなしで String 型の値が返ってきます。もし誤って数値を入れようとすると、コンパイル時にエラーが出るため、実行前に型の間違いに気づくことができます。
これがジェネリクスの大きなメリットです。ジェネリクスなしで同じことをしようとすると、Object 型を使う必要があり、取り出すたびに (String) のようなキャストが必要になります。キャストを間違えると実行時に ClassCastException というエラーが発生しますが、ジェネリクスを使えばこうしたエラーをコンパイル時に防ぐことができます。
ArrayListがまさにこの仕組みを使っています。ArrayList<String> とすることで、String 以外のデータを入れようとするとコンパイルエラーになり、取り出すときもキャスト不要で String 型として使えます。これまで何気なく使っていた <> の意味が、これで理解できたと思います。
メソッドにもジェネリクスを使うことができます。次のように書くと、どんな型の値でも受け取って表示するメソッドを1つで定義できます。
public static <T> void printValue(T value) {
System.out.println("値:" + value);
}
呼び出す際は printValue("テスト") や printValue(42) のように、通常のメソッドと同じように使えます。
まとめ
ジェネリクスを使うことで、型をあとから決められる柔軟なクラスやメソッドを定義できます。キャストが不要になり、型の間違いをコンパイル時に検出できるため、より安全で読みやすいコードが書けるようになります。これまで ArrayList<String> の <> を深く考えずに使っていた方も、今回でその意味が理解できたはずです。ジェネリクスはJavaの標準ライブラリでも広く使われているため、読み解く力がつくと既存のコードが一層理解しやすくなります。
2026/06/25(木) ぱんまる


コメント