そこで、以前の質問の 1 つに答えるメソッドを作成しようとしていました。そのために、私は JLS を読んでいました。
次のクラスがあるとします。
public class A<T> {
public void foo(T param){};
}
public class B extends A<String> {
public void foo(String param){};
}
B.foo
この場合、オーバーライドすることは明らかですがA.foo
、このケースが仕様にどのように適合するかはわかりません。
メソッドのオーバーライドに関して、JLS §8.4.8.1は次のように述べています。
クラス C で宣言されたインスタンス メソッド m1 は、次のすべてが当てはまる場合、クラス A で宣言された別のインスタンス メソッド m2 をオーバーライドします。
C は A のサブクラスです。
m1 の署名は、m2 の署名のサブ署名 (§8.4.2) です。
また:
- m2 が public、protected、または C と同じパッケージ内でデフォルト アクセスで宣言されている、または
- m1 は、m3 が m2 をオーバーライドするように、メソッド m3 (m1 とは異なる m3、m2 とは異なる m3) をオーバーライドします。
明らかに、ポイント 1 と 3 はこのケースで満たされています。JLS でサブ署名の意味をもう少し詳しく見てみましょう。JLS §8.4.2は次のように述べています。
名前と引数の型が同じである場合、2 つのメソッドは同じシグネチャを持ちます。
次の条件がすべて満たされる場合、2 つのメソッドまたはコンストラクタ宣言 M と N は同じ引数の型を持ちます。
それらは同じ数の仮パラメータを持っています (ゼロの可能性があります)
それらは同じ数の型パラメーターを持っています (おそらくゼロ)
A1, ..., An を M の型パラメーターとし、B1, ..., Bn を N の型パラメーターとする。N の型の Bi の各発生を Ai に名前変更した後、対応する型変数の境界は次のようになります。 M と N の仮パラメータの型は同じです。
私たちの場合、ポイント 1 は明らかに真です (両方とも 1 つの引数があります)。
ポイント 2 はもう少し曖昧です (ここで、仕様が正確に何を意味するのかわかりません)。どちらのメソッドも独自の型パラメーターを宣言しませんが、クラスをパラメーター化する型変数である which をA.foo
使用します。T
だから私の最初の質問は: このコンテキストでは、クラスで宣言された Type 変数はカウントされますか?
では、それはカウントされないため、ポイント 2 は誤りであると仮定しましょうT
(この場合、ポイント 3 を適用する方法がわかりません)。私たちの 2 つのメソッドは同じ署名を持っていませんが、それは のサブ署名であることを妨げませB.foo
んA.foo
。
JLS §8.4.2のもう少し先には、次のように書かれています。
次のいずれかの場合、メソッド m1 の署名は、メソッド m2 の署名のサブ署名です。
m2 が m1 と同じ署名を持っている、または
m1 の署名は、m2 の署名の消去 (§4.6) と同じです。
ポイント 1 が誤りであることは既に確認済みです。
JLS §4.6によるメソッドの消去署名は ですa signature consisting of the same name as s and the erasures of all the formal parameter types given in s
。したがって、A.foo の消去は でfoo(Object)
あり、B.foo の消去は ですfoo(String)
。これら 2 つは異なる署名であるため、ポイント 2 も偽であり、B.foo は A.foo のサブ署名ではないため、B.foo は A.foo をオーバーライドしません。
それを除いて...
私は何が欠けていますか?私が見ていないパズルのピースがありますか、それともこの場合、仕様は本当に完全ではありませんか?