11

Java のパラメーター化された型では、パラメーターがその境界内にあるかどうかをチェックするルールはどのようにワイルドカードに対して正確に機能しますか?

次のようなクラスがあるとします。

class Foo<T extends Number> {}

コンパイラが受け入れるものを試してみると、次のことがわかります。

  • 無関係なインターフェイス タイプを使用した? extendsワイルドカードが許可されています:Foo<? extends Runnable>は有効です
  • ? extends無関係なクラス タイプを使用するワイルドカードは許可されていません:はFoo<? extends Thread>無効です。Number型がとの両方のサブタイプになることはできないため、これは理にかなっています。Thread
  • ワイルドカードでは、? superワイルドカードの下限は型変数の境界のサブタイプである必要があります:はのサブタイプではないFoo<? super Runnable>ため、許可されません。繰り返しますが、この制限は完全に理にかなっています。RunnableNumber

しかし、これらのルールはどこで定義されているのでしょうか? 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] は単純に のままですNumberXNumber上限 (キャプチャ変換によるもの) であり、サブタイプ規則に従って、 「型変数の直接のスーパータイプは、その境界にリストされている型である」ため、X<: Number(= Bi[A1 := X1, ... , An := Xn]) であるため、このパラメーターはその境界内にあります。(しかし、そうではありません!)

同じ理由に従って、すべてのワイルドカードはその範囲内にあるため、ここで何かが正しくありません...しかし、この理由は正確にどこで間違っていたのでしょうか? これらのルールを正しく適用すると、どのように機能しますか?

4

1 に答える 1

5

ジェネリックの JLS は不完全であり、別の穴を見つけました。型変数の下限はほとんど議論されておらず、X上限Numberと下限を持つことについても仕様に制限はありませんRunnable。彼らはおそらくそれを残しました。

直観的には、型変数の上限と下限の両方を満たす可能な型が少なくとも 1 つ存在する必要があります。そうでない場合、変数とその変数を使用するすべての型は役に立たなくなります。これはほぼ間違いなくプログラミングの誤りであるため、コンパイルは失敗するはずです。

上限と下限が型の空のセットを作成するかどうかを簡単に確認できます。下限のすべてのスーパー タイプが既知です。それらの少なくとも 1 つが上限である必要があります。そうでない場合、両方の境界内にある型はありません。

--

この 2 つのFoo<? extends A>ケースは、仕様で明確に定義されています。Xキャプチャ変換では、上限を持つ新しい型変数がA & Numberあり、仕様は上限について述べていますV1&...&Vm

任意の 2 つのクラス (インターフェースではない) Vi と Vj について、Vi が Vj のサブクラスでない場合、またはその逆の場合、コンパイル時エラーになります。

したがって、A=Thread の場合、キャプチャ変換は失敗します。

于 2011-08-09T22:39:08.793 に答える