Javaのジェネリクスは、型安全性と再利用性を向上させるための機能です。ジェネリクスを使うことで、クラスやメソッドを型引数を持つように定義することができます。これにより、コンパイル時に型の整合性がチェックされ、型キャストの必要性が減少します。
ジェネリクスの基本
ジェネリッククラス
ジェネリッククラスは、型パラメータを持つクラスです。例えば、リストを実装するシンプルなジェネリッククラスは次のように定義できます。
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
ここで、T
は型パラメータであり、クラスのインスタンス化時に具体的な型に置き換えられます。
Box<Integer> integerBox = new Box<>();
integerBox.set(10);
Integer value = integerBox.get();
ジェネリックメソッド
ジェネリックメソッドは、メソッドレベルで型パラメータを持つメソッドです。例えば、2つの要素を交換するメソッドを定義することができます。
public class Util {
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
このメソッドは、任意の型の配列に対して動作します。
Integer[] intArray = {1, 2, 3, 4};
Util.swap(intArray, 1, 2);
ワイルドカード
ジェネリクスには、柔軟性を持たせるためのワイルドカードが存在します。ワイルドカードは、未知の型を表します。
無制限ワイルドカード
無制限ワイルドカードは、任意の型を表します。
public void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
境界ワイルドカード
境界ワイルドカードは、型に制約を持たせることができます。
- 上限境界ワイルドカード:
<? extends T>
は、T
かそのサブクラスの型を表します。 - 下限境界ワイルドカード:
<? super T>
は、T
かそのスーパークラスの型を表します。
public void processList(List<? extends Number> list) {
for (Number elem : list) {
System.out.println(elem);
}
}
ジェネリクスの利点
- 型安全性: コンパイル時に型チェックが行われるため、ランタイムエラーが減少します。
- 再利用性: 同じコードを異なる型で再利用することができます。
- 可読性: 型キャストの必要性が減少し、コードが読みやすくなります。
制限事項
- プリミティブ型: ジェネリクスはプリミティブ型をサポートしていません。
Integer
やDouble
などのラッパークラスを使用する必要があります。 - 静的コンテキスト: ジェネリック型は静的メンバーで使用できません。
- 型消去: コンパイル後、ジェネリクスは型消去により非ジェネリック型に変換されるため、ランタイムには型情報が存在しません。
例: ジェネリックなコレクション
以下は、ジェネリクスを使用したJavaの標準コレクションの例です。
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
stringList.add("World");
for (String s : stringList) {
System.out.println(s);
}
ジェネリクスを使うことで、List
に追加できる型が制限され、型安全なコードが書けます。
Javaのジェネリクスは、コードの安全性と再利用性を高める非常に強力な機能です。これにより、より堅牢でメンテナブルなコードを書くことができます。
コメント