akios @ ウィキ

4.5.1. 型実引数とワイルドカード

最終更新:

akios

- view
管理者のみ編集可

4. 型と値と変数

4.1. 型と変数の種類

4.2. プリミティブ型と値

4.3. 参照型と値

4.4. 型変数

4.5. 引数付き型

4.5.1. 型実引数とワイルドカード

型実引数(type argument)は参照型かワイルドカード(wildcard)のいずれかです。ワイルドカードは型引数に関する知識が部分的にしかない場合に有効です。

TypeArguments:
  < TypeArgumentList >

TypeArgumentList:
  TypeArgument
  TypeArgumentList , TypeArgument

TypeArgument:
  ReferenceType
  Wildcard

Wildcard:
  ? WildcardBoundsopt

WildcardBounds:
  extends ReferenceType
  super ReferenceType

例4.5.1-1. ワイルドカード

import java.util.Collection;
import java.util.ArrayList;

class Test {
    static void printCollection(Collection<?> c) {
                                // a wildcard collection
        for (Object o : c) {
            System.out.println(o);
        }
    }

    public static void main(String[] args) {
        Collection<String> cs = new ArrayList<String>();
        cs.add("hello");
        cs.add("world");
        printCollection(cs);
    }
}

指定された引数cの型であるCollection<Object>の使用は便利なのものではないでしょう。メソッドはCollection<Object>型を持つ実引数式を伴ってしか使うことができず、そのようなことは極めてまれです。逆に、未制限ワイルドカードの使用はコレクションのような類の型を引数として使用させることを可能にしています。

配列の要素型がワイルドカードで引数付けられている例です。:

public Method getMethod(Class<?>[] parameterTypes) { ... }

ワイルドカードは正規の型変数宣言のように明示的な制約として与えらるかも知れません。Bを制約とすると、上限は以下の構文で決定されます。:

? extends B

通常の型変数がメソッドシグネチャーの中で宣言されるにもかかわらず、ワイルドカードを使用する際にはインタフェースは必要ありません。結果として、Bを下限とすると、ワイルドカードの下限は以下の構文で宣言することができます。:

? super B

例4.5.1-2. 制限付きワイルドカード

boolean addAll(Collection<? extends E> c)

ここで、メソッドはインタフェースCollection<E>内で宣言されており、その指定された引数の全ての要素を呼び出されたコレクション内に追加します。自然な流れではCollection<E>cの型として使用するとなりますが、それは不必要な制約を生みます。代替としてはメソッド自身を次のようにジェネリックとして宣言します。:

<T> boolean addAll(Collection<T> c)

このバージョンは十分に柔軟性がありますが、シグネチャー内に1度しか型引数は使われていません。これは型引数は実引数の型や戻り型やスローする型の間のいかなる種類の相互依存性を説明するのに使用できないという事実を表します。このような相互依存性の欠落から、ジェネリックメソッドは悪いスタイルと考えられ、ワイルドカードが好まれます。

Reference(T referent, ReferenceQueue<? super T> queue);

ここで、referentreferentの型Tのスーパータイプの要素型に持つqueueへ挿入されます。Tはワイルドカードの下限です。

以下の1つでも真の場合は2つの型実引数は明示的に異なります。:
  • 実引数が型変数でもワイルドカードでもなく、2つの実引数が同じ型ではない。
  • 一方の型実引数が型変数もしくはワイルドカードでSの上限を伴っており(必要であれば捕捉変換により)、もう一方の型実引数が型変数やワイルドカードではない。そして|S| <: |T|でも|T| <: |S|でもない。
  • 個々の型実引数が型変数やワイルドカードでSとTの上限を伴っている(必要であれば捕捉変換により)。そして|S| <: |T|でも|T| <: |S|でもない。

以下の規則の推移律と遷移律の元でT2によってあらわされる型の集合がT1によって表される型集合の部分集合であることが明白であるとき、型実引数T1が異なる型実引数T2を含んでいるといい、T2 <= T1と書きます。(ここで、<:はサブタイプ化を表します):
  • ? extends T <= ? extends S if T <: S
  • ? super T <= ? super S if S <: T
  • T <= T
  • T <= ? extends T
  • T <= ? super T

ここで簡単に言及した型理論を確立するワイルドカードの関係は興味深いものです。ワイルドカードは実在型(existential type)の制限された形です。ジェネリック型宣言G<T extends B>が与えらえると、G<?>X <: BであるG<X>に相似していると言って構いません。

歴史的に、ワイルドカードはAtsushi IgarashiとMirko Viroliの研究の直接的な派生です。より広範な議論に興味のある読者はOn Variance-Based Subtyping for Parametric Types by Atsushi Igarashi and Mirko Viroli, in the Proceedings of the 16th European Conference on Object Oriented Programming (ECOOP 2002)を参照してください。この研究自体はそれ以前のKresten ThorupとMads Torgersenによる研究(Unifying Genericity, ECOOP 99)や、POOLにおけるPerre Americaの研究(OOPSLA 89)にまでさかのぼる宣言ベースの相違に関する長年の研究に基づいています。

ワイルドカードは前述した論文に述べられている構成物とはある詳細において、IgarashiとViroliが述べた閉鎖演算(close operation)よりもむしろ特に捕捉変換の使用において、異なります。ワイルカードの正式な記事は、オブジェクト指向プログラミング財団の第12回ワークショップ(FOOP 2005)に提出されたMadsTorgersenとErk ErnstとChristian Plesner HanseによるWild FJを参照してください。

4.5.2. 引数付き型のメソッドとコンストラクター

4.6. 型の抹消

4.7. 具象可能型

4.8. 未加工型

4.9. 交差型

4.10. サブタイプ化

4.11. 型の使用箇所

4.12. 変数

目安箱バナー