【Java】ジェネリックについて
ジェネリックとは何か
ジェネリックは、Javaプログラミングにおいて型安全性と再利用性を向上させるために導入された仕組みです。これにより、コードがより堅牢になり、型キャストを明示的に記述する必要が減ります。
例えば、ジェネリックを使う前と後のリスト操作の比較は以下のようになります:
// ジェネリックを使用しない場合
List list = new ArrayList();
list.add("Hello");
String value = (String) list.get(0);
// ジェネリックを使用する場合
List<String> list = new ArrayList<>();
list.add("Hello");
String value = list.get(0); // キャスト不要
ジェネリックの利点
- 型安全性の向上: 不適切な型の使用をコンパイル時に防止します。
- キャスト不要: 明示的なキャストが不要になり、コードが簡潔になります。
- コードの再利用性: 同じコードを異なる型で使用できます。
ジェネリッククラス
ジェネリッククラスは、型パラメータを持つクラスです。以下は簡単な例です:
// ジェネリッククラスの定義
public class Box<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
// 使用例
Box<String> stringBox = new Box<>();
stringBox.set("Java");
System.out.println(stringBox.get());
ジェネリックメソッド
ジェネリックメソッドは、メソッドレベルで型パラメータを定義できます。以下は例です:
// ジェネリックメソッドの例
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
// 使用例
String[] names = {"Alice", "Bob", "Charlie"};
printArray(names);
ワイルドカードの利用
ワイルドカード(?
)は、ジェネリック型に対する柔軟性を提供します。以下の例を見てみましょう:
// ワイルドカードの例
public static void printList(List<?> list) {
for (Object element : list) {
System.out.println(element);
}
}
// 使用例
List<String> stringList = Arrays.asList("A", "B", "C");
printList(stringList);
境界付き型パラメータ
型パラメータに制約を設けることで、特定のクラスまたはインターフェースを継承した型のみを許可できます。
// 境界付き型パラメータの例
public static <T extends Number> double sum(T a, T b) {
return a.doubleValue() + b.doubleValue();
}
// 使用例
System.out.println(sum(10, 20)); // 出力: 30.0
型消去の仕組み
Javaのジェネリックは、コンパイル時に型情報が消去されます。これを「型消去」と呼びます。この仕組みにより、互換性が保たれます。
例えば:
// 実際のバイトコードでは型情報が消える
List<String> list = new ArrayList<>();
list.add("Hello");
// 型消去後
List list = new ArrayList();
list.add("Hello");
実践的な使用例
ジェネリックは、コレクションフレームワークで広く使用されています。
// Mapのジェネリック例
Map<String, Integer> ageMap = new HashMap<>();
ageMap.put("Alice", 30);
ageMap.put("Bob", 25);
for (Map.Entry<String, Integer> entry : ageMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}