0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Javaジェネリックス

Last updated at Posted at 2025-03-02

ジェネリックス(Generics)

ジェネリックスは、クラスやメソッドで使用するデータ型をコンパイル時に指定できる機能です。これにより、型の安全性を保証し、型変換を最小限に抑えることができます。

ジェネリックスを使用する理由

  1. 型の安全性の保証
    コンパイル時に型をチェックすることで、ランタイム時の型エラーを防ぐことができます。
  2. 型変換の不要
    以前はObject型を使用してダウンキャストする必要がありましたが、ジェネリックスを使用すると不要になります。
  3. 再利用性の向上
    様々な型に対応できる汎用的なコードを記述できます。

ジェネリックスの使い方

1. ジェネリックスを使ったクラス

class Box<T> { // <T> : 型パラメータ
    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>(); // T → String に指定
        stringBox.set("Hello");
        System.out.println(stringBox.get()); // Hello

        Box<Integer> intBox = new Box<>(); // T → Integer に指定
        intBox.set(100);
        System.out.println(intBox.get()); // 100
    }
}

2. ジェネリックスを使ったメソッド

class Util {
    public static <T> void print(T value) {
        System.out.println(value);
    }
}

public class Main {
    public static void main(String[] args) {
        Util.print("Hello");  // String
        Util.print(123);      // Integer
        Util.print(3.14);     // Double
    }
}

3. 境界型パラメータ(<T extends Number>)

ジェネリックスの型パラメータTの範囲を制限することができます。

class NumberBox<T extends Number> { // Number またはそのサブクラスのみ許可
    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        NumberBox<Integer> intBox = new NumberBox<>();  // OK
        NumberBox<Double> doubleBox = new NumberBox<>(); // OK
        // NumberBox<String> strBox = new NumberBox<>(); // コンパイルエラー!
    }
}

📌 特徴

  • TNumberまたはそのサブタイプに限定されます。
  • Tは固定された単一の型であるため、setValue()T型の値を追加可能です。

4. ワイルドカード(?)

上限境界ワイルドカード(<`? extends T`>)

TまたはTのサブタイプを許可(読み取り専用)

コレクションを使用する際に、読み取り専用として制限する場合に使用します。

class Printer {
    public static void printList(List<? extends Number> list) {
        for (Number n : list) {
            System.out.println(n);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        List<Integer> intList = List.of(1, 2, 3);
        List<Double> doubleList = List.of(1.1, 2.2, 3.3);
        
        Printer.printList(intList);   // OK
        Printer.printList(doubleList); // OK
    }
}
📌 特徴
  • <? extends Number>Numberのサブタイプを受け入れます。
  • List<? extends Number>List<Integer>List<Double>などを受け取れます。
  • 正確な型が不明なため、値の追加は不可です。

値の追加(書き込み)が不可能な詳しい理由

コンパイラはリストの具体的な型がTのサブタイプのどれなのかを特定できません。

List<? extends Number> list = new ArrayList<Integer>();

list.add(10);  // ❌ コンパイルエラー!

list<? extends Number>のため、どのサブタイプが来るか分かりません。
例えばlist = new ArrayList<Double>();となる場合もあります。
もしlist.add(10);を許可すると、listArrayList<Double>の時に異なる型(Integer)を追加することになります。
この問題を防ぐためにJavaは値の追加を禁止しています。

ただしnullの追加は可能です。

List<? extends Number> list = new ArrayList<Integer>();
list.add(null);  // ✅ OK

nullはどの型にもなれるため、例外的に許可されます。

下限境界ワイルドカード(<? super T>)

TまたはTの親クラスを許可(書き込み可能)

class Adder {
    public static void addNumber(List<? super Integer> list) {
        list.add(10); // OK
    }
}

public class Main {
    public static void main(String[] args) {
        List<Number> numList = new ArrayList<>();
        Adder.addNumber(numList); // OK

        List<Object> objList = new ArrayList<>();
        Adder.addNumber(objList); // OK
    }
}

リストに値を追加できますが、値を読み取る際にはObject型として取得する必要があります。

値をObjectとして読み取る理由

Object obj = numList.get(0);

numList.get(0);の戻り値の型はObjectです。
理由は、<? super Integer>Integerよりも上位の型になる可能性があるためです。
例えば、List<Number>の場合、Number型の値が含まれている可能性があリます。
Javaは型の安全性を保証する必要があるため、最も確実な型であるObjectを返すようになっています。

ジェネリックス型制限 VS 上限境界ワイルドカード

形が似たような感じで、何が違うのかわかりやすく表で整理しました。

比較項目 ジェネリックス型制限 (<T extends Number>) 上限境界ワイルドカード (? extends Number)
値の追加可否 T 型の追加可能 ❌ 追加不可
値の読み取り可否 T 型として読み取り可能 Number 型として読み取り可能
使用目的 型を確定的に制限 特定の型を読み取り専用で使用
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?