简体   繁体   English

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

[英]Java: compile-time resolution and “most specific method” as it applies to variable arity

Could someone help me understand section 15.12.2.5 of the JLS re: most specific method ? 有人可以帮助我理解JLS的第15.12.2.5节:最具体的方法吗?

(bludgeoned cut&paste from JLS follows) (来自JLS的强行剪切和粘贴如下)

In addition, one variable arity member method named m is more specific than another variable arity member method of the same name if either: 另外,一个名为m的变量arity成员方法比另一个具有相同名称的变量arity成员方法更具体:

  • One member method has n parameters and the other has k parameters, where n >= k. 一个成员方法有n个参数,另一个成员方法有k个参数,其中n> = k。 The types of the parameters of the first member method are T1, . 第一个成员方法的参数类型是T1 ,. . . , Tn-1 , Tn[], the types of the parameters of the other method are U1, . ,Tn-1,Tn [],其他方法的参数类型是U1 ,. . . , Uk-1, Uk[]. ,Uk-1,英国[]。 If the second method is generic then let R1 ... Rp p1, be its formal type parameters, let Bl be the declared bound of Rl, 1lp, let A1 ... Ap be the actual type arguments inferred (§15.12.2.7) for this invocation under the initial constraints Ti << Ui,1ik-1, Ti << Uk, kin and let Si = Ui[R1 = A1, ..., Rp = Ap] 1ik; 如果第二种方法是通用的,那么让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; otherwise let Si = Ui, 1ik. 否则让Si = Ui,1ik。 Then: for all j from 1 to k-1, Tj <: Sj, and, for all j from k to n, Tj <: Sk, and, If the second method is a generic method as described above then Al <: Bl[R1 = A1, ..., Rp = Ap], 1lp. 然后:对于从1到k-1的所有j,Tj <:Sj,并且对于从k到n的所有j,Tj <:Sk,并且,如果第二种方法是如上所述的通用方法,那么Al <:Bl [R1 = A1,...,Rp = Ap],1lp。
  • One member method has k parameters and the other has n parameters, where n >= k. 一个成员方法具有k个参数,另一个具有n个参数,其中n> = k。 The types of the parameters of the first method are U1, . 第一种方法的参数类型是U1 ,. . . , Uk-1, Uk[], the types of the parameters of the other method are T1, . ,Uk-1,Uk [],其他方法的参数类型是T1 ,. . ., Tn-1, Tn[]. 。,Tn-1,Tn []。 If the second method is generic then let R1 ... Rp p1, be its formal type parameters, let Bl be the declared bound of Rl, 1lp, let A1 ... Ap be the actual type arguments inferred (§15.12.2.7) for this invocation under the initial constraints Ui << Ti, 1ik-1, Uk << Ti, kin and let Si = Ti[R1 = A1, ..., Rp = Ap] 1in; 如果第二种方法是通用的,那么让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; otherwise let Si = Ti, 1in. 否则让Si = Ti,1in。 Then: for all j from 1 to k-1 , Uj <: Sj, and, for all j from k to n , Uk <: Sj, and, If the second method is a generic method as described above then Al <: Bl[R1 = A1, ..., Rp = Ap], 1lp. 然后:对于从1到k-1的所有j,Uj <:Sj,并且对于从k到n的所有j,Uk <:Sj,并且,如果第二种方法是如上所述的通用方法,则Al <:Bl [R1 = A1,...,Rp = Ap],1lp。

Ignoring the issue generics, does this mean varargs is more important than subtyping, or subtyping is more important than varargs, when deciding whether one method is more specific than another? 忽略问题泛型,这是否意味着varargs比子类型更重要,或者在确定一种方法是否比另一种更具体时,子类型比varargs更重要? I can't figure it out. 我无法弄清楚。

Concrete example: Which of the following compute() methods is "more specific" according to the JLS? 具体示例:根据JLS,以下哪个compute()方法“更具体”?

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));
    }
}

I can't figure out which is "more specific"; 我无法弄清楚哪个是“更具体”; the output prints 输出打印

1
2

I'm confused how to interpret the results. 我很困惑如何解释结果。 When the first argument was a String, the compiler picked the method with the more specific subtype. 当第一个参数是String时,编译器选择具有更具体子类型的方法。 When the first argument was an Object, the compiler picked the method with the fewer number of optional varargs. 当第一个参数是Object时,编译器选择具有较少可选varargs的方法。


NOTE : If you are not reading this section of the JLS, and you are giving an answer that depends on the types of the arguments , you are not helping me. 注意 :如果您没有阅读JLS的这一部分,并且您给出的答案取决于参数的类型,那么您并没有帮助我。 If you carefully read the JLS, other than the parts relating to generics, the definition of "more specific" depends on the declared arguments, not on the actual arguments -- this comes into play in other parts of the JLS (can't find it at the moment). 如果你仔细阅读JLS,除了与泛型相关的部分,“更具体”的定义取决于声明的参数,而不是实际的参数 - 这在JLS的其他部分发挥作用(找不到)它此刻)。

eg for fixed arity methods, compute(String s) would be more specific than compute(Object o) . 例如,对于固定的arity方法, compute(String s)将比compute(Object o)更具体。 But I'm trying to understand the relevant section of the JLS re: variable arity methods. 但我试图理解JLS的相关部分:变量arity方法。

  1. int compute(String s1, Object... others) is more specific when you call compute("hi",y,y) , since String is a subclass of Object. 当你调用compute("hi",y,y)int compute(String s1, Object... others)更具体,因为String是Object的子类。

  2. int compute(Object o1, Object o2, Object... others) is the only match for compute(y,y,y) because the second method receives String as first param, and JLS15Test is not a subclass of String int compute(Object o1, Object o2, Object... others)compute(y,y,y)唯一匹配,因为第二个方法接收String作为第一个参数,而JLS15Test不是String的子类

EDIT 编辑

My answer resides on the basics of specific methods, but your code only compiles because of the ability of the compiler to distinguish between the methods in the way described above. 我的答案取决于具体方法的基础知识,但您的代码只能编译,因为编译器能够以上述方式区分方法。

The following examples will not even compile because of its ambiguity: 以下示例甚至不会编译,因为它的含糊不清:

case 1: 情况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));
}

case 2: 案例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"));
}

More Edit 更多编辑

I didn't get your question well the first two times (and I hope I do this time :) ). 前两次我没有得到你的问题(我希望我这次做:))。

The actual case you are talking about will look like that: 您正在谈论的实际案例将如下所示:

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; }
}

In this case, compute(Object s1, Object others) is indeed more specific then compute(String s, Object... others) (has less parameters) so the output will be 2 indeed. 在这种情况下, compute(Object s1, Object others)确实比compute(String s, Object... others)更具体(参数更少),因此输出确实是2

After reading the JLS multiple times, I finally think I understand this section. 多次阅读JLS后,我终于想到了解这一节。

What they are saying is that if there are two variable-arity methods, for the purposes of deciding which is "more specific", you can consider the one with the shorter argument list to be extended so that is of equal length to the longer one. 他们所说的是,如果有两个变量arity方法,为了决定哪个是“更具体”,你可以考虑扩展一个具有较短参数列表的方法,使其长度与长一个相等。 。 eg 例如

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

can be considered (only for the purposes of "more specific") to be equivalent to 可以考虑(仅用于“更具体”的目的)等同于

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

and then the argument types are compared, one by one, with the latter method being more specific. 然后逐个比较参数类型,后一种方法更具体。

(more rigorously, the first one has n = 3, k = 2, n >= k, with String <: Object [String is a subtype of Object] and the JLS dictates comparing the types directly of each parameter for j between 1 and k-1 [one less than the shorter length], comparing the vararg type of the shorter method signature with the remaining parameters of the longer method.) (更严格的是,第一个具有n = 3,k = 2,n> = k,具有String <:Object [String是Object的子类型]并且JLS规定直接比较每个参数的类型为j在1和之间k-1 [比较短的长度小1],将较短方法签名的vararg类型与较长方法的其余参数进行比较。)

In the following case: 在以下情况中:

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

these would be equivalent (only for the purposes of "more specific") to 这些将是等效的(仅用于“更具体”的目的)

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

and the latter more specific. 而后者更具体。

So variable-arity never trumps subtyping for the purposes of comparing "more specific" methods which are both of variable arity. 所以变量arity从不胜过子类型,以便比较“更具体”的方法,这两种方法都是变量arity。

However, fixed-arity methods are always considered first (JLS 15.12.2.2 and 15.12.2.3) before variable-arity methods. 但是,在变量方法之前,始终首先考虑固定方法(JLS 15.12.2.2和15.12.2.3)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM