简体   繁体   English

使用可变长度参数进行Java重载

[英]Java overloading with variable length arguments

Why there is no compile error in this code: 为什么此代码中没有编译错误:

public class OverloadingVarArgs
{
    public void fun1(int... b)
    {
        System.out.println("int");
    }
    public void fun1(long... a)
    {
        System.out.println("long");
    }
    public static void main(String[] args)
    {
        OverloadingVarArgs obj = new OverloadingVarArgs();
        obj.fun1();
    }

}

But this code gives compile error! 但是这段代码给出了编译错误!

public class OverloadingVarArgs
{
    public void fun1(int... b)
    {
        System.out.println("int");
    }
    public void fun1(boolean... a)
    {
        System.out.println("boolean");
    }
    public static void main(String[] args)
    {
        OverloadingVarArgs obj = new OverloadingVarArgs();
        obj.fun1();
    }
}

I believe there should be compile error in both the case, but this is not so. 我相信在这两种情况下应该存在编译错误,但事实并非如此。

The rules for selecting the correct overloaded method are as follows: 选择正确重载方法的规则如下:

  • Primitive widening uses the smallest method argument possible 原始扩展使用可能的最小方法参数
  • Wrapper type cannot be widened to another Wrapper type 包装类型不能扩展到另一种包装类型
  • You can Box from int to Integer and widen to Object but no to Long 您可以从int到Integer并将其扩展为Object但不包含Long
  • Widening beats Boxing, Boxing beats Var-args. 加宽节拍拳击,拳击节拍Var-args。
  • You can Box and then Widen (An int can become Object via Integer) 你可以Box然后加宽(一个int可以通过整数成为对象)
  • You cannot Widen and then Box (An int cannot become Long) 你不能加宽然后Box(一个int不能变长)
  • You cannot combine var-args, with either widening or boxing 你不能将var-args与拓宽或装箱结合起来

Have a look at that last rule. 看看最后一条规则。 You can not combine widening or boxing with variable length arguments. 不能将扩展或装箱与可变长度参数组合使用。 That means that the types can not be manipulated in any way and you have to perform the comparison as is. 这意味着不能以任何方式操纵类型,您必须按原样执行比较。 int and long can be compared, no problem and the compiler can deduce that int is the smaller of the two. intlong可以比较,没问题,编译器可以推断出int是两者中较小的一个。 As per the first rule, it will go for the smallest method argument possible, hence it has worked out the correct (and only) route to a method. 根据第一条规则,它将寻找可能的最小方法参数,因此它已经计算出一个方法的正确(和唯一)路由。

However, when you get to boolean and int , there exists no comparison method between the two because of Java's strong typing . 但是,当你得到booleanint ,由于Java的强类型 ,两者之间不存在比较方法。 With no knowledge of which type is smallest, the compiler has absolutely no clue which method you mean. 由于不知道哪种类型最小,编译器完全不知道你指的是哪种方法。

More Visual Example 更多视觉示例

Let's take it step by step from the perspective of the compiler. 让我们从编译器的角度一步一步地看待它。 First, with int and long . 首先,使用intlong

int and long int和long

Step 1 - Checking if the parameters match any arguments and if so, which one it matches exactly 步骤1 - 检查参数是否与任何参数匹配,如果匹配,那么它与哪个参数完全匹配

Well, varargs means that you can pass 0 to many arguments. 好吧, varargs意味着你可以传递0到很多参数。 In this case, you've elected to pass 0 arguments, hence your call matches both the int type and the long type. 在这种情况下,您已选择传递0参数,因此您的调用将匹配int类型和long类型。

Step 2 - Attempt to autobox or widen. 第2步 - 尝试自动装箱或加宽。 This should help it work out which one to go for 这应该有助于解决哪一个问题

You're using varargs, so the compiler knows it can't do this, as per the final rule. 您正在使用varargs,因此编译器知道它不能按照最终规则执行此操作。

Step 3 - Attempt to work out which type is smallest 第3步 - 尝试确定哪种类型最小

The compiler is able to compare the type int with the type long . 编译器能够将int类型与long类型进行比较。 From this, it works out that the int is the smallest type. 由此可知, int是最小的类型。

Step 4 - Make the call 第4步 - 拨打电话

With the knowledge that int is the smallest type, it then passes the value to the method for execution. 知道int是最小的类型,然后它将值传递给方法执行。

Okay, and now let's do the same thing with boolean and int . 好的,现在让我们用booleanint做同样的事情。

boolean and int boolean和int

Step 1 - Checking if the parameters match any arguments and if so, which one it matches exactly 步骤1 - 检查参数是否与任何参数匹配,如果匹配,那么它与哪个参数完全匹配

Same story. 相同的故事。 You've passed nothing so match both arguments. 你没有通过任何东西,所以匹配两个参数。

Step 2 - Attempt to autobox or widen. 第2步 - 尝试自动装箱或加宽。 This should help it work out which one to go for 这应该有助于解决哪一个问题

As above, you're not permitted to do this because you used varargs. 如上所述,由于您使用了varargs,因此不允许这样做。

Step 3 - Attempt to work out which type is smallest 第3步 - 尝试确定哪种类型最小

This is the crucial difference. 这是至关重要的区别。 Here, the types are not comparable. 这里的类型具有可比性。 This means that the compiler doesn't know which method you want to call by your parameters or by the smallest type. 这意味着编译器不知道您希望通过参数最小类型调用哪个方法。 Ergo, it has been unable to work out the correct route. 因此,它无法找到正确的路线。

Step 4 - Make the call 第4步 - 拨打电话

Without the knowledge of which method to call, it can not continue execution and throws the appropriate exception. 如果不知道要调用哪个方法,它就无法继续执行并抛出相应的异常。

In your second example, the compiler is unable to determine the most specific method to invoke. 在第二个示例中,编译器无法确定要调用的最具体方法

The gory details are explained in the language spec , but essentially if two variable-arity (var-arg) methods are being compared, then if Method A could accept the arguments passed to Method B, but not the other way around, then Method B is most specific. 血淋淋的细节在语言规范中解释,但基本上如果比较两个变量(var-arg)方法,那么如果方法A可以接受传递给方法B的参数,而不是相反,那么方法B最具体。

In your first example, the rules of primitive sub-typing are applied, which are: 在第一个示例中,应用了原始子类型规则 ,它们是:

double > 1 float double> 1 float

float > 1 long 漂浮> 1

long > 1 int 长> 1 int

int > 1 char int> 1个字符

int > 1 short int> 1

short > 1 byte 短> 1个字节

( Where > 1 means 'direct supertype of' ) 其中> 1表示'直接超类型'

Here we can see that an int is more specific than a long , so your fun1(int... b) method is chosen. 在这里我们可以看到intlong更具体,因此选择了fun1(int... b)方法。

In the second example, the compiler is choosing between an int and boolean . 在第二个示例中,编译器在intboolean之间进行选择。 There is no sub-type relationship between those primiritve types, therefore there is no most specific method and " the method invocation is ambiguous, and a compile-time error occurs. " (last line in 15.12.2.5). 这些原始类型之间没有子类型关系,因此没有最具体的方法,“ 方法调用不明确,发生编译时错误。 ”(15.12.2.5中的最后一行)。

When you have int and long (comparable types), the smallest will be used by default, which is int (since you're not passing an argument) - I think it's because int can be widen to long but long cannot (unless you explicitly cast it), the compiler will select the lowest precision type. 当你有intlong (可比类型)时,默认情况下将使用最小值,这是int (因为你没有传递参数) - 我认为这是因为int 可以加宽到longlong不能(除非你明确 (),编译器将选择最低精度类型。

But when you have boolean and int , the comparison cannot be done and you'll get 但是当你有booleanint ,无法进行比较而你会得到

The method fun1(int[]) is ambiguous for the type OverloadingVarArgs

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

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