Overload Method Priority

I know that this problem has been discussed many times, but I still do not understand.

Check out 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); } } 

The following rule is in my brain:

  • expansion

  • boxing

  • boxing + variable length

In accordance with this rule, I do the following

1.byte wide for int

Now I have int Integer and there are methods that accept Integer and int

2. boxing in battle

Consequently. int Integer and Integer int arguments

I think the arguments are applicable and expected to see

 Integer int 

at the exit.

But i see

 int ... 

why?

+7
java overloading method-overloading
source share
2 answers

Now it’s clear that the var(int...) method is selected, and not var(Integer...) .

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

It is listed in the Java Language Specification in Section 5.3.

5.3. Method call conversion

Conversion of a method call is applied to each argument value into a method or constructor call (§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 let you use _one of_ the following:

  • identity transformation (§5.1.1)
  • extension of primitive conversion (§5.1.2)
  • extension of referenced conversion (§5.1.5)
  • box conversion (§5.1.7), optionally followed by link extension conversion
  • transformation for unpacking (clause 5.1.8), followed by extension of the primitive transformation.

The only option for the compiler:

  • extension of primitive conversion by first argument
  • unboxing conversion in second argument

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

It cannot first transfer the first byte argument to int , and then apply the box transform on the same argument from int to Integer , because two conversions in the sequence are not allowed.

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

The first two phases that the compiler looks through to select the correct overloaded method do not apply to variable argument methods ("arity variable"), but in the third step:

The third stage (§15.12.2.4) allows you to combine overloading with the methods of the arity variable, boxing and unpacking.

Section 15.12.4 is rather complicated, but the rules applicable here:

  • first apply the rules for arguments without arity variable (not applicable in your case)
  • each variable argument in the call must be converted by converting the method call (the piece that I copied above) to the type of the variable argument declaration

So..

  • you are trying to call a method named var with (byte, Integer)
  • the compiler is looking at your var(Integer...) method var(Integer...)
  • he asks: can I convert the first argument, byte , to Integer (the declared type of the argument in the method)
  • he looks at the rules in JLS 5.3. He can apply only one of the transformations from list 5. None of them can directly convert byte to Integer - he cannot perform two steps.
  • So, the compiler decides that it cannot select var(Integer...)
  • then it looks at your other method, var(int...)
  • According to JLS 5.3, it can convert your first argument, byte to int , using extended primitive conversion. This is a check mark.
  • Turning to the second argument, your Integer , he sees that JLS 5.3 allows the compiler to convert it to int using unboxing conversion. So also a tick.
  • This was the last argument, so var(int...) is a good match.
  • Now the compiler goes over to find out if there are more methods matching your call. If this is more, this will result in an ambiguous call error.
  • But there are no more methods named var , so var(int...) is the only applicable method. Now the compiler will generate code to perform the necessary transformations and call this method.
+5
source share

Java can only do “drawer” and “wide”, and not “wide and rectangular”. For example,

  • int → Number [OK!]
    • int boxed for integer extension with number
  • byte → Integer [DOES NOT]
    • The byte must first be expanded to int, and then in the Integer field. Java does not allow this. Note that you cannot do this: -byte-byte for byte, then expand to Integer (Integer is not a superclass of the byte).

So, in your given methods, the byte of the first argument already discards the two Integer methods. Thus, only int is applicable ....

I wrote the following class to demonstrate:

 public class Overload{ public static void primitiveWiden(int x){ System.out.println("int"); } public static void refWiden(Map m){ System.out.println("Map"); } public static void priWideAndBox(Integer o){//doesn't work System.out.println("Object"); } public static void boxAndRefWide(Number n){//it works System.out.println("Number"); } public static void main(String[] args){ byte b =0; int i =0; HashMap m = new HashMap(); primitiveWiden(b); refWiden(m); priWideAndBox(b);//compile error boxAndRefWide(i); } } 
+2
source share

All Articles