こんにちは!
今回は、Javaの中でも特に便利で重要な「ジェネリクス型」についてお話しします。ジェネリクス型を使うと、同じコードでいろんな種類のデータを扱えたり、型のミスを防げたりします。「ちょっと難しそう…」と思うかもしれませんが、具体例を見ながら楽しく学んでいきましょう!
ジェネリクス型って何?
ジェネリクス型は簡単に言うと、「型を柔軟に扱える仕組み」 です。
普段のプログラムでは、「文字だけ」「数字だけ」など、扱うデータの種類が決まっていますよね?
ジェネリクスを使うと、どんな種類のデータでも同じ書き方で使える ようになります!
例えば、荷物を入れる「箱」をイメージしてください。この箱に「リンゴ」でも「バナナ」でも「ペン」でも入れられるようにしたいときに使うのがジェネリクスです!
ジェネリクスを使わないとどうなる?
ジェネリクスを使わない場合、次のような問題が起きます。
import java.util.ArrayList;
public class WithoutGenerics {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 型を指定しないリスト
list.add("Hello"); // 文字列を追加
list.add(123); // 数値も追加
// リストからデータを取り出す
String value = (String) list.get(0); // キャストが必要
System.out.println(value);
}
}
問題点:
- 型を間違えて使ってもエラーが出ない!
- 数字を文字に変えようとすると、プログラムが途中で止まる可能性があります。
- コードがわかりにくい
- データを取り出すたびに「これは○○型だ」と自分でキャストする必要があります。
ジェネリクスを使うとこうなる!
次のコードは、ジェネリクスを使った例です。
import java.util.ArrayList;
public class WithGenerics {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(); // 型を指定したリスト
list.add("Hello"); // 文字列だけ追加できる
// list.add(123); // コンパイルエラー!文字列以外は入れられない
String value = list.get(0); // キャスト不要でそのまま使える
System.out.println(value);
}
}
ジェネリクスを使った場合のメリット:
- 型のミスを防げる
- 最初に「このリストは文字列だけ!」と決めることで、間違ったデータを入れようとするとエラーになります。
- キャスト不要
- 型が決まっているので、いちいちキャストする必要がなくなります。
実際にジェネリクスクラスを作ってみよう!
今度は、自分で「ジェネリクス」を使ったクラスを作ってみましょう。
例えば、「箱」をイメージしてみてください。箱にはいろんなものを入れたいけど、箱ごとに中身を管理したいですよね。
public class Box<T> { // <T> は仮の型
private T value; // T型のデータを持つ
public void setValue(T value) { // T型のデータを箱に入れる
this.value = value;
}
public T getValue() { // 箱からT型のデータを取り出す
return value;
}
public static void main(String[] args) {
Box<String> stringBox = new Box<>(); // 箱の中身を文字列型に
stringBox.setValue("リンゴ");
System.out.println("文字列の箱には: " + stringBox.getValue());
Box<Integer> intBox = new Box<>(); // 箱の中身を整数型に
intBox.setValue(123);
System.out.println("整数の箱には: " + intBox.getValue());
}
}
ここでのポイント:
Box<T>
の<T>
が「型」を意味します。このクラスを使うときに「文字列型」や「整数型」を指定します。- 一つのクラスでどんな型でも扱える汎用的な仕組みを実現できます!
ジェネリクスメソッドも作ってみよう!
ジェネリクスは、クラスだけでなくメソッドにも使えます!
例えば、どんな配列でも中身をすべて表示するメソッドを作ってみましょう。
public class GenericMethod {
public static <T> void printArray(T[] array) { // <T>は型を表す
for (T item : array) {
System.out.println(item);
}
}
public static void main(String[] args) {
String[] stringArray = {"リンゴ", "バナナ", "オレンジ"};
Integer[] intArray = {1, 2, 3};
System.out.println("文字列の配列:");
printArray(stringArray);
System.out.println("整数の配列:");
printArray(intArray);
}
}
ポイント:
<T>
はメソッドの先頭で宣言します。- メソッドを呼び出すとき、
<T>
の型は自動的に判断されます。 - どんな型の配列でも簡単に扱えるようになります!
ワイルドカード(?)を使うともっと便利!
「型は指定したいけど、何か特定の条件は付けたくない」という場合に使えるのがワイルドカードです。
import java.util.ArrayList;
public class WildcardExample {
public static void printList(ArrayList<?> list) { // ワイルドカード
for (Object item : list) {
System.out.println(item);
}
}
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("リンゴ");
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100);
System.out.println("文字列リスト:");
printList(stringList);
System.out.println("整数リスト:");
printList(intList);
}
}
ポイント:
ArrayList<?>
は、「どんな型でもOKなリスト」という意味です。- ワイルドカードを使うと、異なる型のリストも同じメソッドで扱えます!
まとめ
ジェネリクス型は、Javaで汎用的かつ安全なコードを書くための重要な仕組みです。最初は少し難しく感じるかもしれませんが、使いこなせば再利用性が高くミスの少ないコードが書けるようになります!
もっと詳しく知りたい方は、Java公式ドキュメント をチェックしてみてください。
関連する記事はこちら↓↓