4

誰かが JLS re: most specific method のセクション 15.12.2.5 を理解するのを手伝ってくれませんか?

(JLSからの殴打されたカット&ペーストが続きます)

さらに、次のいずれかの場合、m という名前の可変アリティ メンバー メソッドは、同じ名前の別の可変アリティ メンバー メソッドよりも具体的です。

  • 1 つのメンバー メソッドには n 個のパラメーターがあり、もう 1 つのメンバー メソッドには k 個のパラメーターがあります。ここで、n >= k です。最初のメンバ メソッドのパラメータの型は、T1、. . . 、Tn-1、Tn[]、他のメソッドのパラメータの型はU1、.. . 、英国-1、英国[]。2 番目のメソッドがジェネリックの場合、R1 ... Rp p1 をその正式な型パラメーターとし、Bl を Rl の宣言された境界、1lp とし、A1 ... Ap を推論される実際の型引数 (§15.12.2.7) とします。初期制約の下でのこの呼び出しに対して、Ti << Ui,1ik-1, Ti << Uk, kin and let Si = Ui[R1 = A1, ..., Rp = Ap] 1ik; それ以外の場合は、Si = Ui、1ik とします。次に: 1 から k-1 までのすべての j について、Tj <: Sj、および k から n までのすべての j について、Tj <: Sk、および、 2 番目の方法が上記の一般的な方法である場合、Al <: Bl [R1 = A1, ..., Rp = Ap], 1lp.
  • 1 つのメンバー メソッドには k 個のパラメーターがあり、もう 1 つのメンバー メソッドには n 個のパラメーターがあります。ここで、n >= k です。最初のメソッドのパラメーターの型は、U1、. . . 、Uk-1、Uk[]、他のメソッドのパラメータの型はT1、.. 、Tn-1、Tn[]。2 番目のメソッドがジェネリックの場合、R1 ... Rp p1 をその正式な型パラメーターとし、Bl を Rl の宣言された境界、1lp とし、A1 ... Ap を推論される実際の型引数 (§15.12.2.7) とします。初期制約の下でのこの呼び出しに対して、Ui << Ti, 1ik-1, Uk << Ti, kin and let Si = Ti[R1 = A1, ..., Rp = Ap] 1in; それ以外の場合は、Si = Ti, 1in とします。次に: 1 から k-1 までのすべての j について、Uj <: Sj、および k から n までのすべての j について、Uk <: Sj、および 2 番目のメソッドが上記のようなジェネリック メソッドである場合、Al <: Bl [R1 = A1, ..., Rp = Ap], 1lp.

問題のジェネリックを無視すると、これは、あるメソッドが別のメソッドよりも具体的かどうかを判断するときに、可変引数がサブタイプよりも重要であるか、またはサブタイプが可変引数よりも重要であることを意味しますか? 私はそれを理解することはできません。

具体例: compute()JLS によると、次のどの方法が「より具体的」ですか?

package com.example.test.reflect;

class JLS15Test
{
    int compute(Object o1, Object o2, Object... others) { return 1; }
    int compute(String s1, Object... others)            { return 2; }

    public static void main(String[] args) 
    {
        JLS15Test y = new JLS15Test();
        System.out.println(y.compute(y,y,y));
        System.out.println(y.compute("hi",y,y));
    }
}

どちらが「より具体的」かわかりません。出力プリント

1
2

結果をどう解釈するか迷っています。最初の引数が文字列の場合、コンパイラはより具体的なサブタイプを持つメソッドを選択しました。最初の引数がオブジェクトの場合、コンパイラはオプションの可変引数の数が少ないメソッドを選択しました。


注: JLS のこのセクションを読んでおらず、引数の型に依存する回答をしている場合、あなたは私を助けていません。ジェネリックに関連する部分を除いて、JLS を注意深く読むと、「より具体的な」の定義は、実際の引数ではなく、宣言された引数に依存します。これは、JLS の他の部分で機能します (見つからない現時点では)。

たとえば、固定アリティ メソッドの場合compute(String s)は、より具体的になりcompute(Object o)ます。しかし、私は JLS re: variable arity メソッドの関連セクションを理解しようとしています。

4

3 に答える 3

5
  1. int compute(String s1, Object... others)はObject のサブクラスであるcompute("hi",y,y)ため、を呼び出すとより具体的になります。String

  2. int compute(Object o1, Object o2, Object... others)2 番目のメソッドは String を最初のパラメーターとして受け取り、 のサブクラスではないため、 にのみ一致します。compute(y,y,y)JLS15TestString

編集

私の答えは特定のメソッドの基本にありますが、コンパイラが上記の方法でメソッドを区別できるため、コードはコンパイルされるだけです。

次の例は、あいまいさのためにコンパイルさえしません。

ケース 1:

int compute(Object o1, Object o2, Object... others) { return 1; }
int compute(Object s1, Object... others)            { return 2; }

public static void main(String[] args) 
{
    JLS15Test y = new JLS15Test();
    System.out.println(y.compute(y,y,y));
    System.out.println(y.compute("hi",y,y));
}

ケース 2:

int compute(String o1, Object o2, Object... others) { return 1; }
int compute(Object s1, String... others)            { return 2; }

public static void main(String[] args) 
{
    JLS15Test y = new JLS15Test();
    System.out.println(y.compute("hi","hi","hi"));
}

もっと編集

最初の 2 回はあなたの質問をうまく聞き取れませんでした (今回はうまくいきますように :) )。

あなたが話している実際のケースは次のようになります。

public class Test {
    public static void main(String[] args)
    {
        Test t = new Test();
        int a = t.compute("t", new Test());
        System.out.println(a);
    }

    int compute(String s, Object... others) { return 1; }
    int compute(Object s1, Object others)   { return 2; }
}

この場合、compute(Object s1, Object others)実際にはより具体的であるcompute(String s, Object... others)(パラメーターが少ない) ため、出力は2確かになります。

于 2011-05-16T21:10:04.473 に答える
1

JLS を何度も読んだ後、ようやくこのセクションを理解できたと思います。

彼らが言っていることは、2 つの可変アリティ メソッドがある場合、どちらが「より具体的」であるかを決定する目的で、引数リストが短い方を拡張して、長い方と同じ長さになると考えることができるということです。 . 例えば

int compute(Object o1, Object o2, Object... others)
int compute(String s1, Object... others)

と同等であると見なすことができます (「より具体的な」目的でのみ)

int compute(Object o1, Object o2, Object... others)
int compute(String s1, Object,    Object... others)

次に、引数の型が 1 つずつ比較され、後者の方法がより具体的です。

(より厳密には、最初のものは n = 3、k = 2、n >= k、String <: Object [String は Object のサブタイプ] であり、JLS は 1 とk-1 [短い長さより 1 少ない]、短いメソッド シグネチャの vararg 型を長いメソッドの残りのパラメーターと比較します。)

次の場合:

int compute(Object o1, Object o2, String... strings)
int compute(Object o1, String... strings)

これらは (「より具体的な」目的でのみ) と同等です。

int compute(Object o1, Object o2, String... strings)
int compute(Object o1, String,    String... strings)

後者はより具体的です。

したがって、変数アリティは、可変アリティの両方である「より具体的な」メソッドを比較する目的で、サブタイピングを決して打ち負かしません。

ただし、可変アリティ メソッドの前に、固定アリティ メソッドが常に最初に考慮されます (JLS 15.12.2.2 および 15.12.2.3)。

于 2011-05-16T21:42:37.053 に答える
0

リテラル "hi" はコンパイル時に String であることがわかっているため、2 番目の compute 呼び出しは 2 を出力します。String は Object よりも具体的であるため、コンパイラは 2 番目のメソッド シグネチャを選択します。

于 2011-05-16T21:13:03.073 に答える