8

jdk6 に関する素晴らしい本「Java scjp 認定のプログラマー ガイド」を読んでいて、ジェネリック オーバーライドに関するセクションがあります。その上で、サブシグネチャと同等のオーバーライドについて説明し、引用した同等のオーバーライドの例をいくつか説明します。

クラスに次の 3 つのジェネリック メソッド宣言があるとします。

static <T> void merge (MyStack<T> s1, MyStack<T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? extends T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? super T> s2) { /*...*/ }

消去後、3 つのメソッドすべてのシグネチャは次のようになります。merge(MyStack, MyStack) つまり、メソッドのシグネチャはオーバーライドと同等であるため、これらのメソッドはオーバーロードされません。

これらのメソッドがオーバーライドと同等であることに完全に同意するわけではありません。実際、メソッドには「消去による名前の衝突」があると思いますが、他のメソッドのサブシグネチャではありません…おそらく間違っているので、これについて少し説明したいと思います。

サブ署名の定義は、それらの間のサブ署名ではないと私に思わせます。

JSL 6 #8.4.2 メソッド署名 ( http://docs.oracle.com/javase/specs/jls/se6/html/classes.html#8.4.2 )

名前と引数の型が同じである場合、2 つのメソッドは同じシグネチャを持ちます。次の条件がすべて満たされる場合、2 つのメソッドまたはコンストラクタ宣言 M と N は同じ引数の型を持ちます。

  • 彼ら。同じ数の仮パラメータを持つ (おそらくゼロ)

  • それらは同じ数の型パラメーターを持っています (おそらくゼロ)

  • <A1,...,An>M の正式な型パラメーターを とし、 N<B1,...,Bn>の正式な型パラメーターとする。

メソッド m1 の署名は、m2 が m1 と同じ署名を持っているか、m1 の署名が m2 の署名の消去と同じである場合、メソッド m2 の署名のサブ署名です。

...

2 つのメソッド シグネチャ m1 と m2 は、m1 が m2 のサブシグネチャであるか、m2 が m1 のサブシグネチャである場合、オーバーライド等価です。

JSL 8 # 8.4.2。メソッド署名 ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2 )

2 つのメソッドまたはコンストラクター M と N は、同じ名前、同じ型パラメーター (存在する場合) (§8.4.4) を持ち、N の仮パラメーター型を型パラメーターに適合させた後、同じシグネチャを持ちます。 M の、同じ仮パラメーター型。

次のいずれかの場合、メソッド m1 の署名は、メソッド m2 の署名のサブ署名です。

  • m2 が m1 と同じ署名を持っている、または

  • m1 の署名は、m2 の署名の消去と同じです。

2 つのメソッド シグネチャ m1 と m2 は、m1 が m2 のサブシグネチャであるか、m2 が m1 のサブシグネチャである場合、オーバーライド等価です。

編集1

簡単に言えば、私の疑問は、消去に関するサブ署名の定義から、「消去のない1つの署名は、他の署名からの消去と等しい」..「消去後の両方の署名が等しい」ということではない..その微妙ですが重要です(ちなみに、オーバーライドと同等の定義はサブシグネチャの定義に基づいているため、サブシグネチャに関して質問します)

4

1 に答える 1

1

TL;DR

私の意見では、この本の文言はここではうまくまとまっていません。オーバーロードは、 JLS (8.4.9) (言い換えると、同じ名前の 2 つのメソッドが存在するがオーバーライドと同等でない場合、それらはオーバーロードされます)に従って、オーバーライドと同等の否定の観点から定義されます。

ただし、指定された例は、メソッドがオーバーライドと同等ではなく、他の理由 (名前の衝突 - JLS 8.4.8.3で指定された特定のコンパイル時エラー) でコンパイル時エラーを引き起こすため、オーバーロードしないものです。


前文

私が理解しているように、あなたはこの文節の正確な意味論について疑問を投げかけています:

「...または、m1 の署名は m2 の署名の消去と同じです」

と組み合わせて

m1 と m2 は、m1 が m2 のサブシグニチャであるか、m2 が m1 のサブシグニチャである場合、オーバーライドと同等です。


あなたの本は、これが次のように解釈されるべきであることを暗示しています

「または、 m1署名の消去は、m2 の署名の消去と同じです」

(太字イタリック体の単語を追加)。

あなたはそれを次のように解釈しますが、

「または、m1 の署名 (消去なし) は、m2 の署名の消去と同じです」

あなたの解釈は正しいです。 私は文が曖昧だとは思わないので、最初の解釈 (つまり、両方の署名の消去が同じである) は正しくないと思います。ここで私の意見に重みを加えるために、この関連する回答をご覧になることをお勧めします(私の理解も確認したかったので見つけました)。


答え(しかし…)

あなたが引用している本のセクションは、実際にはオーバーロードについて説明しようとしています。

今-オーバーロードについて考えるとき-JLS(8.4.9)は次のように述べています:

クラスの 2 つのメソッド (両方が同じクラスで宣言されているか、両方がクラスによって継承されているか、または 1 つが宣言され 1 つが継承されているかに関係なく) が同じ名前を持ちますが、シグネチャがオーバーライド等価でない場合、メソッド名は次のようになります。過負荷。

これは、少なくとも Java 6 から一貫していますoverride-equivalent

わかりました-メソッドは厳密にはオーバーライドと同等ではないため、オーバーロードされます。右?

違う。

8.4.8.3のそのセクションのすぐ上にあるため、JLSは特定のコンパイル時エラーを挿入します。

型宣言 T にメンバー メソッド m1 があり、T または T のスーパータイプで宣言されたメソッド m2 が存在し、次のすべてが真である場合、コンパイル時エラーになります。

  • m1 と m2 は同じ名前です。

  • m2 は T からアクセスできます。

  • m1 の署名は、m2 の署名のサブ署名 (§8.4.2) ではありません。

  • m1 または一部のメソッド m1 オーバーライドの署名 (直接的または間接的) には、m2 または一部のメソッド m2 オーバーライドの署名 (直接的または間接的) と同じ消去があります。

これがあなたの例のシナリオです。そのセクションのすぐ下に、なぜそれが必要なのかが明確にされています。

ジェネリックは消去によって実装されるため、これらの制限が必要です。上記のルールは、同じクラスで同じ名前で宣言されたメソッドは、異なる消去を持つ必要があることを意味します。また、型宣言が同じジェネリック インターフェイスの 2 つの異なる呼び出しを実装または拡張できないことも意味します。

サイドノート

Java では静的メソッドのオーバーライドが許可されないため (むしろ、サブクラスのメソッドのシグネチャがスーパークラスのメソッドのシグネチャを隠す可能性があるため)、この本の例は奇妙なものです。これにより、私の見解では、オーバーライドと同等ではないという概念が学習者にとって少しトリッキーになります。ただし、を削除しstaticても、デモンストレーションしようとしている効果を確認できます。

于 2015-07-06T11:12:03.230 に答える