Menu
Coddy logo textTech

ジェネリクス入門

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 53/87。

値を保存し、後で取得するクラスを作成する必要があるとします。Generics がなければ、型ごとに個別のクラスを記述しなければなりません。Integer 用に1つ、String 用に1つ、Double 用に1つ、という具合です。これではコードの重複が発生し、保守が大変になります。

Generics は、型安全性を維持しながら、任意の型で動作するクラスやメソッドを記述できるようにすることで、この問題を解決します。プレースホルダー(型パラメーター と呼ばれます)を定義し、クラスを使用するときに実際の型に置き換えます。

// ジェネリクスなし - Objectを使用し、キャストが必要
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // 手動キャストが必要

// ジェネリクスあり - 型安全、キャスト不要
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // キャスト不要

山かっこ <T> は型パラメーターを表します。List<String> と記述すると、この list には文字列だけが含まれることをコンパイラに伝えています。整数を追加しようとすると、実行時に失敗するのではなく、コンパイラがすぐにエラーを検出します。

Generics には2つの重要な利点があります。明示的な casting が不要になり、実行時ではなく compile 時に型 errors を検出できます。これにより、コードの安全性と読みやすさの両方が向上します。これからのレッスンでは、独自のジェネリッククラスとジェネリックメソッドを作成する方法を学びます。

challenge icon

チャレンジ

簡単

Object とキャストを使用する古い方法と、型安全なジェネリクスを使用する新しい方法を比較して、ジェネリクスの力を示すシンプルなストレージシステムを作成しましょう。

違いを実際に確認するために、3つのファイルを作成します。

  • OldBox.java:ジェネリクス以前の方法で値を格納する class を作成します。OldBox には、型が Object の private な field content を持たせます。Object を accepts して格納する constructor と、Object を返す getContent() method を含めます。この approach は機能しますが、値を取得するときに casting が必要です。
  • GenericBox.java:次に、ジェネリクスを使用した modern で型安全なバージョンを作成します。GenericBox の宣言では、type parameter T を使用します。型が T の private な field contentT の値を accepts する constructor、および型 T を返す getContent() method が必要です。この class を使用すると casting は不要です。
  • Main.java:両方の approach を並べて示します。2つの入力、つまり word(String)と number(integer)を受け取ります。

    まず、old approach を使用します。word を格納する OldBox を作成し、String への cast を使って取得して、OldBox (with cast): [value] と print します。

    次に、generic approach を使用します。同じ word を格納する GenericBox<String> を作成し、casting せずに取得して、GenericBox (no cast): [value] と print します。

    続いて、整数で generics が機能することを示します。number を格納する GenericBox<Integer> を作成し、それを取得して、GenericBox Integer: [value] と print します。

    最後に、blank line を print し、その後に Type safety: Generics catch errors at compile time! を print します。

入力は順番に2つ受け取ります。word(String)と number(parse する integer としての String)です。

重要な違いに注目してください。OldBox では、(String) box.getContent() のように cast し、正しい type を取得できたことを期待する必要があります。GenericBox では、compiler が type を認識するため、casting は不要です。これが generics の中心的な利点である、面倒な casting なしの型安全性です。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine();
        int number = Integer.parseInt(scanner.nextLine());
        
        // TODO: word を格納する OldBox を作成する
        // Retrieve with cast to String and print: "OldBox (with cast): [value]"
        
        // TODO: word を格納する GenericBox<String> を作成する
        // Retrieve without casting and print: "GenericBox (no cast): [value]"
        
        // TODO: Create a GenericBox<Integer> storing the number
        // Retrieve and print: "GenericBox Integer: [value]"
        
        // TODO: 空行を出力してから、次を出力する:
        // "Type safety: Generics catch errors at compile time!"
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Javaオンラインコンパイラ