Java のパラメーター化された型では、パラメーターがその境界内にあるかどうかをチェックするルールはどのようにワイルドカードに対して正確に機能しますか?
次のようなクラスがあるとします。
class Foo<T extends Number> {}
コンパイラが受け入れるものを試してみると、次のことがわかります。
- 無関係なインターフェイス タイプを使用した
? extends
ワイルドカードが許可されています:Foo<? extends Runnable>
は有効です ? extends
無関係なクラス タイプを使用するワイルドカードは許可されていません:はFoo<? extends Thread>
無効です。Number
型がとの両方のサブタイプになることはできないため、これは理にかなっています。Thread
- ワイルドカードでは、
? super
ワイルドカードの下限は型変数の境界のサブタイプである必要があります:はのサブタイプではないFoo<? super Runnable>
ため、許可されません。繰り返しますが、この制限は完全に理にかなっています。Runnable
Number
しかし、これらのルールはどこで定義されているのでしょうか? Java 言語仕様のセクション 4.5 を見ると、インターフェイスとクラスを区別するものは何もありません。JLSの私の解釈を適用すると、Foo<? super Runnable>
有効であると言われます。だから私はおそらく何かを誤解しました。これが私の試みです:
JLSのそのセクションから:
パラメーター化された型は、クラスまたはインターフェイス名 C と、実際の型引数リスト <T1 , ... , Tn> で構成されます。C がジェネリック クラスまたはインターフェイスの名前でない場合、または実際の型引数リスト内の型引数の数が C の宣言された型パラメーターの数と異なる場合、コンパイル時エラーになります。クラスまたはインターフェイス タイプの場合、明示的に除外されない限り、ジェネリック バージョンも含めます。このセクションでは、 A1 、 ... 、 An を C の仮型パラメーターとし、 Bi を Ai の宣言された境界とする。[Ai := Ti] という表記は、1 <= i <= n の場合、型変数 Ai を型 Ti に置き換えることを示し、この仕様全体で使用されます。
P = G<T1, ..., Tn> をパラメーター化された型とします。P がキャプチャ変換 (§5.1.10) の結果、型 G<X1, ..., Xn> になった後、実際の型引数 Xi, 1 <= i <= n ごとに、 Xi <: Bi[A1 := X1, ..., An := Xn] (§4.10)、またはコンパイル時エラーが発生します。
それを P = Foo<? super Runnable>
: に適用すると、C = Foo
、n = 1、T1 =? super Runnable
および B1 =が得られNumber
ます。
キャプチャ変換の場合、キャプチャ変換の定義のこの部分が適用されます。
Ti が ? 形式のワイルドカード型の引数の場合 super Bi の場合、Si は上限が Ui[A1 := S1, ..., An := Sn] で下限が Bi の新しい型変数です。
これにより、 G<X1, ..., Xn> =Foo<X>
が与えられます。ここX
で、 は上限Number
と下限を持つ新しい型変数ですRunnable
。そのような型変数を明示的に禁止しているものは見当たりません。
B1 = には型変数がないNumber
ため、 Bi[A1 := X1, ..., An := Xn] は単純に のままですNumber
。
X
はNumber
上限 (キャプチャ変換によるもの) であり、サブタイプ規則に従って、 「型変数の直接のスーパータイプは、その境界にリストされている型である」ため、X
<: Number
(= Bi[A1 := X1, ... , An := Xn]) であるため、このパラメーターはその境界内にあります。(しかし、そうではありません!)
同じ理由に従って、すべてのワイルドカードはその範囲内にあるため、ここで何かが正しくありません...しかし、この理由は正確にどこで間違っていたのでしょうか? これらのルールを正しく適用すると、どのように機能しますか?