14
public class MyClass {

    private String string;
    private Object[] objects;

    // constructor 1
    public MyClass(String string, Object... objects) {
        this.string = string;
        this.objects = objects;
    }

    // constructor 2
    public MyClass(String string) {
        this.string = string;
    }

    public static void main(String[] args) {
        MyClass myClass = new MyClass("foobar");
    }

}

In that case, how did the Java compiler decide to use constructor 2 instead of constructor 1? Why no The constructor ... is ambiguous or a similar error occurs?

PS: the question works with classic methods too.

sp00m
  • 47,968
  • 31
  • 142
  • 252

5 Answers5

7

A var-args method/constructor will be chosen only if there is no non-var-arg method/constructor. So it is clear that why compiler chooses MyClass(String string).

Juvanis
  • 25,802
  • 5
  • 69
  • 87
  • 2
    This isn't true for all cases, see this snippet from [JLS 15.2.2](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2): _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._ – Keppil Oct 29 '12 at 11:19
  • Throw in auto-(un)boxing for some more confusion... Method resolution has become tricky since Java 5. I think the cases @Keppil mentions result in a compiler warning at least. – Thilo Oct 29 '12 at 11:22
5

It's always the most specific method that is called.

new MyClass("foobar");

searches to call that constructor which takes an object of type String as it's only argument.

and, var-args method will be used iff matching non-var-args method doesn't exist.

Azodious
  • 13,752
  • 1
  • 36
  • 71
1

As I understand varargs constructors and methods are only syntax sugar, which transforms to array declarations. So your constructor 1 during compilation would be nearly equal to:

public MyClass(String string, Object[] objects) {
    this.string = string;
    this.objects = objects;
}

It means, that if you want to construct instance of MyClass by following code:

MyClass obj = new MyClass("Hello", "1", "2");

It would be equal to:

MyClass obj = new MyClass("Hello", new Object[]{"1", "2"} );
stemm
  • 5,960
  • 2
  • 34
  • 64
  • 2
    Not really equal, because that constructor would not match the call (whereas the varargs one does, just with a lower priority). – Thilo Oct 29 '12 at 11:19
  • 1
    @ Thilo, yes, you're right. I've just wanted to explain concept on example, but couldn't found better explanation. – stemm Oct 29 '12 at 11:24
0

The JVM will look for Exact matching for passing values to variables in methods/constructor, if it's not able find exact match it will treat the values as Object.

NPKR
  • 5,368
  • 4
  • 31
  • 48
0

jls-15.12.2 states that compiler will first look best match for without autoboxing or var agrs. Constructor #2 fits in your case.

If it had not been there, the first autoboxing will be applied, i.e. any method with parameter super class of String i.e. Object will be callled.

   // constructor 2
    public MyClass(Object string) {
        this.string = string.toString();
    }

Now, even after applying autoboxing, compiler is not able to find best match, it will go for var args. So, if you remove constructor 2 from your code, first constructor will be called.

Sumit Singh
  • 15,743
  • 6
  • 59
  • 89
Lokesh Gupta
  • 463
  • 5
  • 8