【问题标题】:Overloaded methods for java certification examjava认证考试重载方法
【发布时间】:2021-04-09 15:14:14
【问题描述】:

我正在准备 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);
    }
}

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"

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

【问题讨论】:

    标签: java methods overloading java-11


    【解决方案1】:

    如果您删除方法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)

    【讨论】:

    • 因此,原语被拆箱/装箱到它们的类型。 int 不能装箱到 Longint 将被装箱到 Integer。而Integer 不是Long,因此我没有任何匹配项。
    • @kee07420 完全正确。更准确地说,int 不能自动装箱为 Long,但它可以装箱为 Long:Long.valueOf(2).
    • 在装箱/拆箱时基元类型 wrap 其他基元是否只发生在这些类型的 Class 版本中?
    • 有趣的事实:当您编写 Long l = 0L; var result = Calculator.add(1, true? 2: l); 时,int 的值 2 可以 提升为 long 并一次性装箱为 Long。更令人兴奋的是,当您使用Long l = 0L; Integer i = 2; var result = Calculator.add(1, true? i: l); 时,可以将iInteger 拆箱为int,将值提升为long 并将其装箱为Long
    【解决方案2】:

    重载适用性规则植根于conversion规则(JLS Ch5,“Conversions and Contexts”。)定义了不同的conversions(原始加宽(int to long),装箱(int to Integer),引用扩大(String to Object)等)。

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

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

    可变参数的情况适用于松散的上下文,因为从intlong 的原始转换扩大了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-18
      • 2018-01-28
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-05
      相关资源
      最近更新 更多