4

See the code below:

// 1st method
private static void method(Object o){
    System.out.println("object method");
}
// 2nd method
private static void method(Object... o){
    System.out.println("object vararg method");
}
public static void main(String [] ar){
    method(null); // 1st call
    Integer value=null; 
    method(value); // 2nd call
}

I expected 1st call and 2nd call both should invoke 1st method, thought null will prefer to match Object than Object... vararg. But I am wrong.

  • 1st call invoked 2nd method
  • 2nd call invoked 1st method

My question is why or how null matches to Object... vararg and not Object in my code?

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Sridhar
  • 1,832
  • 3
  • 23
  • 44

2 Answers2

3

JLS 15.12.2 explains this exact scenario:

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 1
    Did you seriously re-open a closed duplicate just to add your own answer? – Jeroen Vannevel Apr 24 '15 at 12:47
  • 2
    @JeroenVannevel I re-opened it since the supposed duplicate answer you linked this question to didn't answer this question at all. And since I just found a reference in the JLS that explains this behavior, I opened it and posted an answer. – Eran Apr 24 '15 at 12:49
  • And on top of that the other given answer is wrong in this case. – Dennis Ich Apr 24 '15 at 12:54
  • 1
    @DennisIch In what way is it wrong? Granted it doesn't address the first and second phase resolution that is explained here, but it still explains the basic "match the most specific signature, if possible" logic. – Kayaman Apr 24 '15 at 12:56
  • Well wrong is maybe the wrong word but it does not really answer the question in this specific null case and only provides some brief explanation for the general case which has its value but i think this one is the correct answer and therefore good he reopened it. Despite i think we should not discuss the other answer under this one. – Dennis Ich Apr 24 '15 at 16:02
2

Because Object... is essentially Object[] and since null is a valid Object[], it will match to the most specific one.

If you had 3 methods with first having Object parameter, the second having SubClass param and the last having SubSubClass param, the last one would be chosen.

Whereas if you add a method with a String parameter to your original code, you will get a compile time error, since there is no longer a single most specific match for null.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • 1
    I'd say that the `null` value is implicitly convertible to `Object[]` - if you use `instanceof` itself, that will fail. – Jon Skeet Apr 24 '15 at 12:32
  • Overload resolution between Foo(Object) and Foo(String) is perfectly possible: the latter will be chosen. – Jeroen Vannevel Apr 24 '15 at 12:34
  • @JeroenVannevel Not if he adds it to his example code, which already has a method with a subclass of `Object` as a parameter. – Kayaman Apr 24 '15 at 12:35
  • I think `null` can refer to either, and the warning from Eclipse reads : The argument of type null should explicitly be cast to `Object[]` for the invocation of the varargs method `method(Object...)` from type `TestClass`. It could alternatively be cast to `Object` for a varargs invocation. – Gyan Apr 24 '15 at 12:36
  • 1
    lars@lars-laptop:~/Documents$ javac Test.java `Test.java:11: warning: non-varargs call of varargs method with inexact argument type for last parameter; method(null); // 1st call ^ cast to Object for a varargs call cast to Object[] for a non-varargs call and to suppress this warning 1 warning` – lschuetze Apr 24 '15 at 12:36
  • @Gyanapriya No, null can't refer to either one, since it would cause a compile time error for ambiguity instead of a warning. – Kayaman Apr 24 '15 at 12:58