java认证考试的重载方法

kee*_*420 3 java methods overloading java-11

我正在准备 Java 认证考试,我不明白的一件事如下:

class Calculator {
    public static long add(int a, long... b) {
        System.out.println("int a, Var args long b");
        int total = a;
        for (long val : b) {
            total += val;
        }
        return total;
    }
    public static long add(int a, Long b) {
        System.out.println("int + Long");
        return a + b;
    }
}
public class OverloadTests {
    public static void main(String[] args) {
        var result = Calculator.add(1, 2);
        System.out.println("result = " + result);
    }
}
Run Code Online (Sandbox Code Playgroud)

Java 文档(https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2)说:

1- 第一阶段执行重载决议,不允许装箱或拆箱转换,或使用可变参数方法调用。如果在此阶段找不到适用的方法,则处理继续到第二阶段

2- 第二阶段在允许装箱和拆箱的同时执行重载决议,但仍排除使用可变参数方法调用。如果在此阶段未找到适用的方法,则处理继续到第三阶段。

3- 第三阶段允许重载与可变数量方法、装箱和拆箱相结合。

所以,有了这些规则,我认为这应该发生:

  • Calculator.add(1, 2);寻找(int, int)签名,但没有找到。它还查找(int, long)(int, float)以及(int, double)与此订单。由于我们在第 1 步中,我们没有在寻找可变参数,我们不应该有匹配项。
  • 在这一步中,它执行装箱/拆箱。正如我们所做的那样(int, Long),我希望结果是"int + Long"
  • 在这一步中,它还寻找可变参数,如果上一步不存在,它应该已经找到了"int a, Var args long b".

我在这里缺少什么?我期待结果是"int + Long",但它是"int a, Var args long b"

编辑:代码取自Java SE 11 Developer 1Z0-819 OCP Course - Part 1作者命名的 Udemy 课程Tim Buchalka

k31*_*159 7

如果删除该方法,add(int a, long... b)您会发现您的代码将无法编译,因为add(int a, Long b)无法调用剩余的方法,add(1, 2)因为 2 是一个 int 并且原始 int 不能装箱到 Long 中。同样,该语句Long a = 2;无效。因此唯一匹配的候选是add(int a, long... b)

  • 有趣的事实:当你写“Long l = 0L;”时 var result = Calculator.add(1, true? 2: l);`,“int”值“2”*可以一次性提升为“long”并装箱为“Long”。更令人兴奋的是,当您使用“Long l = 0L;”时 整数 i = 2;var result = Calculator.add(1, true? i: l);`,可以将`i`从`Integer`取消装箱为`int`,将值提升为`long`并将其装箱为`Long`。 (5认同)

Bri*_*etz 5

重载适用性的规则植根于转换规则(JLS Ch5,“转换和上下文”)。定义了不同的转换(原始加宽(int 到 long)、装箱(int 到 Integer)、引用加宽(String 到 Object) ), ETC)。

在任何给定情况下,任何给定转换可能适用也可能不适用,具体取决于上下文上下文包括赋值上下文、方法调用上下文、强制转换上下文等,重载决策第一阶段和后面阶段的区别就是严格调用上下文松散调用上下文的区别。

让您困惑的可能是即使在松散的调用上下文中add(int, Long)也不适用(int, int)。这是因为 (JLS 5.3) 后跟装箱转换的加宽基元转换不是调用上下文中允许的转换之一。如果您调用add(0, 0L)它,它将适用(拳击转换)。

varargs 情况适用于松散上下文,因为存在从int到的扩大原始转换long