【问题标题】:Primitive vararg parameters in method overloading方法重载中的原始可变参数
【发布时间】:2017-03-23 13:41:09
【问题描述】:

原始人又来了,打破了规则,我以前学过。好吧,在技术上不是原始的,而是由它们组成的。

我了解到,只要没有比 rest 更具体的方法,编译时错误就会发生在这里。

public static void caller(){
    z5();  // Error. Neither Integer, nor String is more specific
    z5(null);  // Error for the same reason
}
public static void z5(Integer...integers){
    System.out.println("Integer z5 called");
}
public static void z5(String...strings){
    System.out.println("String z5 called");
}

现在图元出现了。

public static void caller(){
    z1(null);  // Error cuz [I, [J, [F all are subclass of Object.
    z1();  // SURPRISINGLY works and calls the int one. WHY?
}
public static void z1(int...integers){
    System.out.println("int z1 called");
}
public static void z1(long...longs){
    System.out.println("long z1 called");
}
public static void z1(float...floats){
    System.out.println("float z1 called");
}

此处出现预期的编译时错误。

public static void caller(){
    z1(null);  // Error
    z1();  // Error
}
public static void z1(int...integers){
    System.out.println("int z1 called");
}
public static void z1(boolean...bools){
    System.out.println("bool z1 called");
}

现在我的问题是,int[]、float[] 或任何原始数组都不是原始类型,那么为什么它们的处理方式与其他引用类型不同?

--更新--

@john16384你不认为我读过你的“可能重复”Varargs in method overloading in Java

那里的最佳答案是 您不能将 var-args 与加宽或装箱结合使用。除了我忘了提,OP 的代码贴在那里,在我的 jdk 7 上运行良好。

究竟发生了什么,适用于 (int...is) & (float...fs) 但不适用于 (Integer...is) & (Float. ..fs) 而不是 (int...is) & (boolean...bool)

【问题讨论】:

    标签: java arrays overloading variadic-functions primitive


    【解决方案1】:

    引用 JLS 中关于在多个方法适用时的可变参数调用:

    15.12.2.5。选择最具体的方法

    如果多个成员方法既可访问又适用于 方法调用,需要选择一个来提供 运行时方法分派的描述符。 Java 编程 语言使用选择最具体方法的规则。

    非正式的直觉是一种方法比 如果可以传递第一个方法处理的任何调用,则另一个 在另一个没有编译时错误的情况下。在诸如 显式类型的 lambda 表达式参数(第 15.27.1 节)或变量 arity 调用(§15.12.2.4),允许一些灵活性来适应 一个签名到另一个。

    这里的重要部分是如何将方法定义得更具体。它基本上说int...long... 更具体,因为您可以传递给第一个方法的任何值也可以传递给第二个方法。

    这也适用于不传递参数的情况。 int... 将是最具体的(它甚至会将byte... 视为更具体!)。

    public static void main(String[] args) {
        bla();
    }
    
    private static void bla(long... x) {}
    private static void bla(int... x) {}
    private static void bla(short... x) {}
    private static void bla(byte... x) {}   // <-- calls this one
    

    在创建重载boolean... 时也出现错误的原因是,现在调用哪一个是不明确的,并且编译器在到达必须选择最具体的方法之前就停止了。

    【讨论】:

    • 我在链接的副本中没有看到很好的描述,所以我删除了该评论。
    • 但是,如果我用它们各自的 Wrapper 类替换原语,它会给我一个错误。为什么不调用 Short 的方法?正如您刚刚描述的那样,它不是更具体吗? @john16384
    • @Shashwat 那是因为它们是对象,它们遵循对象的子类型规则。 Short 不是 Integer 的子类。
    • @Anurag Awashti 在 JLS 4.10 中,它解释了子类型。对于原语,JLS 4.10.1 中定义了规则
    • @Anurag Awashti 我没有对此进行广泛检查,但原语不能为空,因此它必须将空值装箱为一种包装器类型,并且由于有多个选项,所以它会模棱两可.如果您随后尝试强制转换它,它将再次失败,因为 null 无法再次拆箱为原语。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多