Menu
CoddyTech

ジェネリックメソッド

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

ジェネリッククラスを使うとクラス全体がさまざまな型で動作しますが、ジェネリックにする必要があるのが単一のメソッドだけの場合もあります。ジェネリックメソッドは、クラスレベルのジェネリクスとは独立した、独自の型パラメーターを宣言します。

型パラメーターは、メソッドシグネチャで戻り値の型の前に置かれます。

public class Utility {
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }
}

String[] names = {"Alice", "Bob"};
Integer[] numbers = {1, 2, 3};

Utility.printArray(names);    // String[] に対応
Utility.printArray(numbers);  // Integer[] に対応

修飾子と戻り値の型の間に置かれた<T>に注目してください。これは、この特定のメソッドの型パラメーターとしてTを宣言しています。コンパイラーは、渡した引数から実際の型を推論します。

ジェネリックメソッドはジェネリック型を返すこともできます。

public static <T> T getFirst(T[] array) {
    if (array.length > 0) {
        return array[0];
    }
    return null;
}

String first = getFirst(new String[]{"a", "b"});  // "a"を返す

必要に応じて、複数の型パラメーターを使用できます。

public static <K, V> void printPair(K key, V value) {
    System.out.println(key + ": " + value);
}

printPair("Age", 25);        // String と Integer
printPair(1, "First");       // Integer と String

ジェネリックメソッドは、ジェネリッククラスを作成せずに、柔軟で再利用可能な処理を必要とするユーティリティクラスで特に役立ちます。

challenge icon

チャレンジ

簡単

ジェネリックメソッドの柔軟性を示すユーティリティツールキットを作りましょう。あらゆる型で使える再利用可能なメソッドを持つクラスを作成し、ジェネリックメソッドがジェネリッククラスとは独立して存在できることを確かめます。

コードは2つのファイルに分けて整理します。

  • ArrayUtils.java:配列を扱うジェネリックメソッドを含むユーティリティクラスを作成します。このクラスには、次の3つの静的ジェネリックメソッドを定義します。

    getLast - 型Tの配列を受け取り、最後の要素を返すジェネリックメソッドです。配列が空の場合は、nullを返します。

    swap - 型Tの配列と2つの整数インデックスを受け取り、それらの位置にある要素を入れ替えるジェネリックメソッドです。このメソッドは何も返しません。

    printWithLabel - 型パラメーターKとVを持つジェネリックメソッドです。型Kのラベルと型Vの値を受け取り、次の形式で出力します:[label]: [value]

  • Main.java:ジェネリックメソッドを使ってみましょう!2つの単語(文字列)と2つの数値(整数)の、合計4つの入力を受け取ります。

    まず、両方の単語を含むString[]配列を作成します。getLastを使って最後の要素を取得し、Last word: [result]と出力します。

    次に、両方の数値を含むInteger[]配列を作成します。swapを呼び出してインデックス0と1の要素を入れ替え、その後After swap: [first], [second]と出力します。

    最後に、printWithLabelを2回呼び出して、2つの型パラメーターを持つジェネリックメソッドを使ってみましょう。

    • 1回目は、最初の単語をラベル、最初の数値を値として渡します。
    • 2回目は、最初の数値をラベル、2番目の単語を値として渡します。

入力は、最初の単語、2番目の単語、最初の数値、2番目の数値の順に4つ受け取ります。

各メソッドが戻り値の型の前に<T>または<K, V>を付けて、それぞれ独自の型パラメーターを宣言していることに注目してください。コンパイラーは渡された引数から実際の型を推論するため、メソッドを呼び出すときに型を明示する必要はありません。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み取る
        String firstWord = scanner.nextLine();
        String secondWord = scanner.nextLine();
        int firstNumber = scanner.nextInt();
        int secondNumber = scanner.nextInt();
        
        // TODO: 両方の単語を含むString[]配列を作成する
        
        // TODO: ArrayUtils.getLastを使って最後の要素を取得する
        // 出力: "Last word: [result]"
        
        // TODO: 両方の数値を含むInteger[]配列を作成する
        
        // TODO: ArrayUtils.swapを呼び出して、インデックス0と1の要素を入れ替える
        // 出力: "After swap: [first], [second]"
        
        // TODO: firstWordをラベル、firstNumberを値としてArrayUtils.printWithLabelを呼び出す
        
        // TODO: firstNumberをラベル、secondWordを値としてArrayUtils.printWithLabelを呼び出す
    }
}
quiz icon腕試し

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

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

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