Search code examples
javaoverloadingtype-promotion

Type Promotion and Method Overloading (Multiple Options)


What are the factors that determine which method will be executed when there are multiple acceptable methods because of type promotion?

Here's example code

public class Demo {
  public static void main(String[] args) {
    byte a = 100;
    long b = 10000;
    test(a, b);
  }

  public static void test(long a, double b) {
    System.out.println("Method 2");
  }

  public static void test(int a, float b) {
    System.out.println("Method 1");
  }
}

The output is: Method 1 as written but Method 2 if I comment out test(int a, float b)

Why is that? Does it try to do the least amount of type promotion? Does it try to promote argument 1, then argument 2? Is it based on some type of priority?

I've seen this question: How method-overloading and primitive types works?, which includes the statement:

  1. If more than one method was identified, pick the most specific one.

I'm asking for more specifics behind how the final method to be executed is selected amongst all the possible methods. I am aware that type promotion happens, but if there are multiple options after type promotion, how does the compiler determine the final method? In other words, from the statement above, what is more specific?


Solution

  • Although the question and answer that you linked to already covers this to some extent, one can have a look at the more specific case here (pun intended). Particulary, the relevant "path to the decision" referring to the (somewhat complex) description of 15.12.2.5. Choosing the Most Specific Method in the JLS.

    The section first of all says:

    The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

    This already is very helpful, because you can see that whatever you're passing to the test(int, float) method could also be passed to the test(long, double) method. So the first one is more specific.

    But referring to the spec:

    One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:

    • m2 is not generic, and m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k).

    ...

    A type S is more specific than a type T for any expression if S <: T

    The latter refers to the 4.10. Subtyping section where the the supertype relation :> is specified as the reflexive and transitive closure of the direct supertype relation >1, and the latter includes, for primitive types

    • double >1 float
    • long >1 int

    So the method test(int, float) is more specific than test(long, double) because int is a subtype of long and float is a subtype of double.


    (Note that the concept of "subtypes" here is also applied to primitive types, and not only to "inheritance between classes")