2

I feel that these are applicable:

JLS 15.12.2.4. Phase 3: Identify Methods Applicable by Variable Arity Invocation

JLS 15.12.2.5. Choosing the Most Specific Method

But JLS language is so complex that I cannot understand the point.

void f(Integer... arg) { System.out.println("Integer..."); }

void f(int... arg) { System.out.println("int..."); }

void test() {
    f((short)1); // int... called 
    f(1); // c.ERR

I seemingly understand that one (besides this was ALREADY ANSWERED here), though the answer did not describe all the details (the exact sequence - what arguments are tried) of the entire overload resolution process - anyway my question is mainly in the second code snippet (int.. vs long...). But let me go into details of the above snippet:

f((short)1) - no exact match, so primitive short is first widened (no match found), then short is boxed into Short (no exact match found), Short is widened (Number, Object) - no match, now comes the third phase (varargs) => the following is tried:

  • short... (no exact match => try primitive widening)
  • int... (exact match found, but don't stop, search further!)
  • long..., float..., double... (no match => try boxing)
  • Short..., Number..., Object...

As no other match found - it compiles OK.

f(1) - no exact match, so primitive int is first widened (no match found), then int is boxed into Integer (no exact match found), Integer is widened (Number, Object) - no match, now comes the third phase (varargs) => the following is tried:

  • int... (exact match found, but don't stop, search further!)
  • long..., float..., double... (no match => try boxing)
  • Integer... (now ambiguous), Number..., Object...

As two possible matches found - we have a compile Error.

void f(long... arg) { System.out.println("long..."); }

void f(int... arg)  { System.out.println("int..."); }

void test() {
    f((byte)1); // int... called 
    f(1);       // int... called 
}

f(byte) - as comes the third phase (varargs) => the following is tried:

  • byte... (no match => try primitive widening)
  • short..., int... (match found, but look further), long... (shall be ambigouos error, but it is not!), float..., double... (now also do boxing with subsequent reference widening to look for more possible matches to flag compile error "ambiguous")
  • Byte..., Number..., Object...

As two possible matches found - shall be a compile Error (but it is not).

My guess is that there are 4 procedures (exact primitive match, primitive widening, boxing and exact reference match, reference widening) and the compiler stops if it found a match during some procedure (the procedure is not continued), but tries all other subsequent procedures. In this case compiler stopped at procedure 2 (only int... matches, but not long...), procedures 3 and 4 yielded no match.

The above-quoted answer on SO offers the following criteria:

for one parameter to be more specific than the other, the type of that parameter must be a subtype of the other method's parameter.

It may work for reference types, but not in case of primitives.

I seem to understand 15.12.2. Compile-Time Step 2: Determine Method Signature. But in my case we have "The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing." - but the detailes of this is the problem.

enter image description here enter image description here enter image description here

4

1 回答 1

1

至于评论

为了使一个参数比另一个参数更具体,该参数的类型必须是另一个方法参数的子类型。

请注意,这适用于原始类型,请参阅https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.10 规范中给出的关系意味着 int 是一个更具体类型比长。

来自https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5

如果 S <: T (§4.10),对于任何表达式,类型 S 比类型 T 更具体。

于 2019-08-17T13:45:30.607 回答