The HIRO Says

If you smell what The HIRO is cooking!!!

Generics で型に "?" を指定すると?続き

石田さんに詳しいことを調べていただいたので、それをベースにコードを組んでみました。
(石田さんありがとうございました m(_ _)m)


コードの実装例

引数の Set に格納されている要素数を返すメソッドを考えてみましょう。

    private int countElements(Set<?>  set) {
        if (set == null) {
            return 0;
        }
        return set.size();
    }


"<?>" と定義すると、任意の型パラメータの Set を引数に取ることができます。
("<E>" ではコンパイルエラーになります。後述。)
また、"<?>" をつけると、メソッド内で Set の内容をいじれなくできます。(add() などを呼べなくなります)
(内容をいじらせなくするという効果が ( ゚д゚))


一応、引数定義を "Set set" としても、特別コンパイル時に警告も出ず、想定通りに動作します。
でもそれだと、Set を引数に与えても、メソッド内で "set.add(new Date())" という操作が可能になるので、型の安全性が損なわれてしまいます。
なので、"<?>" をつけておいた方がよいです。


動作確認

以下のテストコードは正常終了します。
任意の型パラメータの Set を使用できることが確認できます。
※ちなみに、"<?>" のことを、英語で "unbounded wildcard type" と言います。

    public void testUnboundedWildcardType() {

        // ?String の Set
        Set stringSet = null;
        assertEquals(
                0,
                countElements(stringSet));

        stringSet = new TreeSet();
        assertEquals(
                0,
                countElements(stringSet));

        stringSet.add("a");
        assertEquals(
                1,
                countElements(stringSet));

        stringSet.add("b");
        assertEquals(
                2,
                countElements(stringSet));


        // ?Integer の Set
        Set integerSet = null;
        assertEquals(
                0,
                countElements(integerSet));

        integerSet = new TreeSet();
        assertEquals(
                0,
                countElements(integerSet));

        integerSet.add(1);
        assertEquals(
                1,
                countElements(integerSet));

        integerSet.add(2);
        assertEquals(
                2,
                countElements(integerSet));
    }

新たな疑問

何で countElements(Set<E> set) と定義するとコンパイルエラーになるのか?
これは明日じっくり調べてみます。