018 オブジェクト指向の深化(ジェネリクスとワイルドカード) 017 解答例

public class Pair<T extends Comparable<T>> {
    private T first;
    private T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return first;
    }

    public T getSecond() {
        return second;
    }

    public T getMax() {
        return (first.compareTo(second) > 0) ? first : second;
    }

    public static void main(String[] args) {
        // 整数型のペア
        Pair<Integer> intPair = new Pair<>(3, 7);
        System.out.println("Max of Integers: " + intPair.getMax());

        // ダブル型のペア
        Pair<Double> doublePair = new Pair<>(5.6, 2.3);
        System.out.println("Max of Doubles: " + doublePair.getMax());

        // 文字列型のペア
        Pair<String> stringPair = new Pair<>("apple", "orange");
        System.out.println("Max of Strings: " + stringPair.getMax());
    }
}

この例では、Pair クラスがジェネリクスであり、TComparable インターフェースを実装する型に制約されています。getMax メソッドは、firstsecond の要素を比較し、大きい方を返します。main メソッドでは、整数型、ダブル型、文字列型のペアを作成し、それぞれの最大値を取得しています。

ジェネリクスの制約

ジェネリクスの制約(Bounds)は、ジェネリクスを使用する際に型に対する条件を指定する仕組みです。主に2つの制約があります。

  1. 上限境界(Upper Bounded):
    • ジェネリクス型パラメータが指定した型またはそのサブタイプである必要があります。
    • 上限境界は extends キーワードを使用して指定します。
    • 例: class Box<T extends Number> { /* ... */ }
  2. 下限境界(Lower Bounded):
    • ジェネリクス型パラメータが指定した型またはそのスーパータイプである必要があります。
    • 下限境界は super キーワードを使用して指定します。
    • 例: class Container<T super Integer> { /* ... */ }

上限境界の例:

class Box<T extends Number> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

この例では、Box クラスの型パラメータ TNumber クラスまたはそのサブクラスである必要があります。例えば、Box<Integer>Box<Double> は有効ですが、Box<String> は無効です。

下限境界の例:

class Container<T super Integer> {
    private T value;

    public Container(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

この例では、Container クラスの型パラメータ TInteger クラスまたはそのスーパークラスである必要があります。例えば、Container<Number>Container<Object> は有効ですが、Container<String> は無効です。

ジェネリクスの制約は、型安全性を保ちつつ柔軟性を持たせるための重要な概念です。上限境界や下限境界を利用することで、ジェネリクスを使用する際に特定の型のみを受け入れたり、特定の型のサブタイプを制限することができます。これにより、プログラムがより予測可能で、型に関するエラーがコンパイル時に検知されやすくなります。

ジェネリクスの制約を適切に利用することで、柔軟性と型安全性のバランスを取りながら、再利用可能で拡張性のあるコードを構築することができます。型に関する制約は、コードの品質とメンテナンス性を向上させ、プログラムの堅牢性を高める一助となります。

「018 オブジェクト指向の深化」問題集リスト