4

有人可以帮我理解JLS re: most specific method 的第 15.12.2.5 节吗?

(来自 JLS 的大棒剪切和粘贴如下)

此外,一个名为 m 的变量 arity 成员方法比另一个同名的变量 arity 成员方法更具体,如果:

  • 一个成员方法有 n 个参数,另一个有 k 个参数,其中 n >= k。第一个成员方法的参数类型为 T1, 。. . , Tn-1 , Tn[], 其他方法的参数类型为 U1, . . . , Uk-1, Uk[]。如果第二种方法是泛型的,则令 R1 ... Rp p1 为其形式类型参数,令 Bl 为 Rl、1lp 的声明边界,令 A1 ... Ap 为推断的实际类型参数(第 15.12.2.7 节)对于初始约束下的此调用 Ti << Ui,1ik-1, Ti << Uk, kin 并让 Si = Ui[R1 = A1, ..., Rp = Ap] 1ik; 否则令 Si = Ui, 1ik。则:对于从 1 到 k-1 的所有 j,Tj <: Sj,并且,对于从 k 到 n 的所有 j,Tj <: Sk,并且,如果第二种方法是如上所述的通用方法,则 Al <: Bl [R1 = A1,...,Rp = Ap],1lp。
  • 一个成员方法有 k 个参数,另一个有 n 个参数,其中 n >= k。第一种方法的参数类型为 U1, . . . , Uk-1, Uk[], 其他方法的参数类型为 T1, . . ., Tn-1, Tn[]。如果第二种方法是泛型的,则令 R1 ... Rp p1 为其形式类型参数,令 Bl 为 Rl、1lp 的声明边界,令 A1 ... Ap 为推断的实际类型参数(第 15.12.2.7 节)对于初始约束下的此调用 Ui << Ti, 1ik-1, Uk << Ti, kin 并让 Si = Ti[R1 = A1, ..., Rp = Ap] 1in; 否则令 Si = Ti, 1in。然后:对于从 1 到 k-1 的所有 j,Uj <: Sj,并且对于从 k 到 n 的所有 j,Uk <: Sj,并且,如果第二种方法是如上所述的通用方法,则 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 methods 的相关部分。

4

3 回答 3

5
  1. int compute(String s1, Object... others)调用时更具体compute("hi",y,y),因为String它是 Object 的子类。

  2. int compute(Object o1, Object o2, Object... others)唯一的匹配项,compute(y,y,y)因为第二种方法接收 String 作为第一个参数,并且JLS15Test不是String

编辑

我的答案是基于特定方法的基础知识,但您的代码只能编译,因为编译器能够以上述方式区分方法。

以下示例由于含糊不清甚至无法编译:

情况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"));
}

更多编辑

前两次我没有很好地回答你的问题(我希望这次我能做到:))。

您正在谈论的实际案例将如下所示:

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后,我终于认为我理解了这一部分。

他们的意思是,如果有两种可变参数方法,为了确定哪种方法“更具体”,您可以考虑扩展参数列表较短的方法,使其与较长的方法具有相同的长度. 例如

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)

然后逐个比较参数类型,后一种方法更具体。

(更严格地说,第一个具有 n = 3,k = 2,n >= k,其中 String <: Object [String is a subtype of Object] 并且 JLS 规定直接比较 j 在 1 和k-1 [比较短长度小一],比较较短方法签名的可变参数类型与较长方法的剩余参数。)

在以下情况下:

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

第二个计算调用打印 2,因为在编译时已知文字“hi”是一个 String,因此编译器选择了第二个方法签名,因为 String 比 Object 更具体。

于 2011-05-16T21:13:03.073 回答