Java:编译时解析和"最具体的方法",因为它适用于变量arity

Jas*_*n S 4 java variadic-functions jls

有人可以帮助我理解JLS的第15.12.2.5节:最具体的方法吗?

(来自JLS的强行剪切和粘贴如下)

另外,一个名为m的变量arity成员方法比另一个具有相同名称的变量arity成员方法更具体:

  • 一个成员方法有n个参数,另一个成员方法有k个参数,其中n> = k.第一个成员方法的参数类型是T1 ,. ..,Tn-1,Tn [],其他方法的参数类型是U1 ,. ..,Uk-1,英国[].如果第二种方法是通用的,那么让R1 ... Rp p1成为它的形式类型参数,让Bl成为Rl的声明边界,1lp,让A1 ... Ap成为推断的实际类型参数(§15.12.2.7)对于这种在初始约束下的调用Ti << Ui,1ik-1,Ti << Uk,kin和let 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.

忽略问题泛型,这是否意味着varargs比子类型更重要,或者在确定一种方法是否比另一种更具体时,子类型比varargs更重要?我无法弄清楚.

具体示例: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));
    }
}
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚哪个是"更具体"; 输出打印

1
2
Run Code Online (Sandbox Code Playgroud)

我很困惑如何解释结果.当第一个参数是String时,编译器选择具有更具体子类型的方法.当第一个参数是Object时,编译器选择具有较少可选varargs的方法.


注意:如果您没有阅读JLS的这一部分,并且您给出的答案取决于参数的类型,那么您并没有帮助我.如果你仔细阅读JLS,除了与泛型相关的部分,"更具体"的定义取决于声明的参数,而不是实际的参数 - 这在JLS的其他部分发挥作用(找不到)它此刻).

例如,对于固定的arity方法,compute(String s)将更具体compute(Object o).但我试图理解JLS的相关部分:变量arity方法.

MBy*_*ByD 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));
}
Run Code Online (Sandbox Code Playgroud)

案例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"));
}
Run Code Online (Sandbox Code Playgroud)

更多编辑

我前两次没有得到你的问题(我希望我这次做:)).

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

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; }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,compute(Object s1, Object others)确实更具体compute(String s, Object... others)(参数较少),因此输出2确实如此.