Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
343 views
in Technique[技术] by (71.8m points)

overloading method priority in java

I know that this problem discussed many times but I don't understand anyway.

Research this code:

public class Main {  
    public static void var(Integer x, int y) {  
        System.out.println("Integer int");  
    }  


    public static void var(int... x) {  
        System.out.println("int... x");  
    }  

    public static void var(Integer... x) {  
        System.out.println("Integer...");  
    }  

    public static void main(String... args) {   
        byte i = 0;  
        Integer i2 = 127;  
        var(i, i2);  
    }  
} 

In my brain following rule:

  1. widening

  2. boxing

  3. boxing+varargs

According this rule I make next actions

1.byte wides to int

Now I have int Integer and there are exist method takes Integer and int

2.make boxing

Hence. int -> Integer and Integer -> int arguments

I think that arguments are applicable and expected to see

Integer int

in output.

But I see

int ...

why?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It is now clear that the method var(int...) is selected and not var(Integer...).

The reason is that only certain conversions are allowed to be applied, and it can only be one of these conversions from the list, not a chain of conversions. The java compiler is not allowed to do a widening primitive conversion first, and then a boxing conversion.

It's specified in the Java Language Specification in section 5.3

5.3. Method Invocation Conversion

Method invocation conversion is applied to each argument value in a method or constructor invocation (§8.8.7.1, §15.9, §15.12): the type of the argument expression must be converted to the type of the corresponding parameter.

Method invocation contexts allow the use of _one of_ the following:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)
  • a boxing conversion (§5.1.7) optionally followed by widening reference conversion
  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.

The only option for the compiler is to do:

  1. a widening primitive conversion on the first argument
  2. an unboxing conversion on the second argument

That turns (byte, Integer) into (int, int).

It cannot first turn the first argument byte into an int and then apply a boxing conversion on the same argument from int to Integer because two conversions in sequence are not allowed.

Let's go back one step to find out how the compiler selects which overloaded method to invoke. That is described in JLS 15.12.2. (15.12.1 describes how to find the class or interface to search, but we already know that we want to invoke a static method in class Main)

The first two phases that a compiler goes through to select the right overloaded methoddo not apply to variable argument ("variable arity") methods, but the third phase does:

The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

Section 15.12.4 is quite complicated, but the rules that apply here are:

  • first apply the rules for non-variable arity arguments (not applicable in your case)
  • each variable argument in the invocation must be convertable by method invocation conversion (the piece that I copied above) to the type of the variable argument declaration

So..

  1. you try to invoke a method named var with (byte, Integer)
  2. the compiler looks at your method var(Integer...)
  3. it asks: can I convert the first argument, a byte, to Integer (the declared type of the argument in the method)
  4. it looks at the rules in JLS 5.3. It can only apply one of the conversions from the list of 5. None of them can convert a byte to an Integer directly - it cannot do two steps.
  5. So the compiler decides that it cannot select var(Integer...)
  6. then it looks at your other method, var(int...)
  7. According to JLS 5.3, it can convert your first argument, the byte to an int using a widening primitive conversion. That's a check mark.
  8. Moving on to the second argument, your Integer, it sees that JLS 5.3 allows the compiler to convert it to an int using an unboxing conversion. So that's also a check mark.
  9. That was the last argument, so var(int...) is a good match.
  10. The compiler now moves on to see if there are more methods that match your invocation. If there are more that do, that will result in an ambiguous-invocation error.
  11. But there are no more methods with the name var, so var(int...) is the only applicable method. The compiler will now generate code to do the necessary conversions and invoke that method.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...