Menu
Coddy logo textTech

ジェネリッククラス

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

ジェネリクスがなぜ便利なのかを理解したところで、独自のジェネリッククラスを作成してみましょう。ジェネリッククラスは、クラス名の後のアングルブラケット(山括弧)内に1つ以上の型パラメータを宣言し、それをクラス全体で使用することができます。

class Box<T> {
    private T content;
    
    public void set(T content) {
        this.content = content;
    }
    
    public T get() {
        return content;
    }
}

T は型パラメータです。これは、インスタンスを作成する際に実際の型に置き換えられるプレースホルダーです。任意の名前を使用できますが、慣習的には 1 文字の大文字が使われます。Type の T、Element の E、Key の K、Value の V などです。

ジェネリッククラスをインスタンス化する際、山括弧の中に実際の型を指定します:

Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get();  // キャストは不要です

Box<Integer> intBox = new Box<>();
intBox.set(42);
Integer num = intBox.get();

右側の <>(ダイヤモンド演算子)に注目してください。Javaは宣言から型を推論します。また、複数の型を扱う必要があるクラスに対して、複数の型パラメータを使用することもできます:

class Pair<K, V> {
    private K key;
    private V value;
    
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    
    public K getKey() { return key; }
    public V getValue() { return value; }
}

Pair<String, Integer> pair = new Pair<>("age", 25);
challenge icon

チャレンジ

簡単

ジェネリッククラスの威力を示すギフト登録システムを構築しましょう。あらゆる種類のギフトアイテムを保持できる柔軟なストレージシステムと、複数の型パラメータを使用してギフト名とその詳細をペアにするレジストリを作成します。

コードは3つのファイルに分けて構成します:

  • GiftBox.java: あらゆる種類のギフトを包むことができるジェネリッククラスを作成します。GiftBox<T> は、型 T のプライベートフィールド item と、初期値が false のプライベートフィールド wrapped (boolean) を持つ必要があります。アイテムを受け取るコンストラクタ、アイテムを返す getItem() メソッド、wrapped を true に設定する wrap() メソッド、およびラップされた状態を返す isWrapped() メソッドを含めてください。ラップされた状態に応じて、[item] (wrapped) または [item] (unwrapped) のいずれかを返す getStatus() メソッドを追加します。
  • Registry.java: 受取人とギフトをペアにする、2つの型パラメータを持つジェネリッククラスを作成します。Registry<K, V> は、型 K のプライベートフィールド recipient と、型 V のプライベートフィールド gift を持つ必要があります。両方の値を受け取るコンストラクタ、ゲッターメソッド getRecipient() および getGift()、そして [recipient] -> [gift] を返す getEntry() メソッドを含めてください。
  • Main.java: ギフトレジストリを完成させましょう!受取人の名前 (String)、ギフトの説明 (String)、およびギフトの価値 (ドルを表す整数) の3つの入力を受け取ります。

    まず、ギフトの説明を含む GiftBox<String> を作成します。wrap() メソッドを使用してそれを包み、そのステータスを出力します。

    次に、ギフトの価値(ギフトカードの金額を表す)を含む GiftBox<Integer> を作成します。これは包まずに、ステータスを出力してアンラップ状態であることを示します。

    最後に、受取人の名前とギフトの説明をペアにする Registry<String, String> を作成し、レジストリエントリを出力します。

受取人の名前、ギフトの説明、ギフトの価値(整数)の順に3つの入力を受け取ります。

同じ GiftBox クラスが String 型と Integer 型の両方でシームレスに動作することに注目してください。これがジェネリクスの素晴らしさです!また、Registry クラスは、複数の型パラメータによって、任意の2つの型の間で柔軟なペアリングを作成できることを示しています。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み込む
        String recipientName = scanner.nextLine();
        String giftDescription = scanner.nextLine();
        int giftValue = scanner.nextInt();
        
        // TODO: giftDescription を含む GiftBox<String> を作成する
        // TODO: wrap() メソッドを使用してそれを包む
        // TODO: getStatus() を使用してそのステータスを表示する
        
        // TODO: giftValue を含む GiftBox<Integer> を作成する
        // TODO: こちらは包まずに、そのステータスを表示する(unwrapped と表示されるはずです)
        
        // TODO: 受取人とギフトの説明をペアにする Registry<String, String> を作成する
        // TODO: getEntry() を使用してレジストリエントリを表示する
    }
}
quiz icon腕試し

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

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