1

Given these two constructors:

SomeClass(int... params)
{
   // Do things
}

SomeClass(long... otherParams)
{
   // Do other things
}

What happens when an object foo is instantiated?

SomeClass foo = new SomeClass();

Is the undefined default constructor somehow called? Or is one of those constructors with an empty array called? If so, what’s the precedent?

I’ve done some basic testing and found that if a constructor without parameters is defined then that will be called. Otherwise, it appears that an ambiguous one is called.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
Anilla
  • 151
  • 8
  • 1
    Only a class with no explicit constructors at all gets a default constructor. Your class does not have a default constructor. – John Bollinger Jan 09 '19 at 20:03
  • @Andreas With further testing (using primitive types) it seems the type with the lowest amount of byte size is called. This is purely speculative though, I’d like a definitive answer. – Anilla Jan 09 '19 at 20:10
  • "With further testing (using primitive types) it seems the type with the lowest amount of byte size is called." - Add the following constructor and you'll see that it won't compile: `SomeClass(boolean... moreParams)` – Jacob G. Jan 09 '19 at 20:27

2 Answers2

2

As per this very good answer in "Varargs in method overloading in Java" question below are the rules used by Java compiler for selecting the method signature to invoke. They are based on JLS 5.3. Method Invocation Conversion docs.

  1. Primitive widening uses the smallest method argument possible
  2. Wrapper type cannot be widened to another Wrapper type
  3. You can Box from int to Integer and widen to Object but no to Long
  4. Widening beats Boxing, Boxing beats Var-args.
  5. You can Box and then Widen (An int can become Object via Integer)
  6. You cannot Widen and then Box (An int cannot become Long)
  7. You cannot combine var-args, with either widening or boxing

Because both constructors are var-args (rule 7) the compiler will fall back to other rules and select the method that uses the smallest type (rule 1).

You can confirm this behaviour with following code:

static class SomeClass {
  SomeClass(long... value) { System.out.println("Long"); }
  SomeClass(int... value) { System.out.println("Int"); }
  SomeClass(byte... value) { System.out.println("Byte"); }
}

public static void main(String[] args) throws Exception {
  SomeClass o = new SomeClass(); // Byte
}

The precise subtype relation between primitives types used in rule 1 is explained in JLS 4.10.1. Subtyping among Primitive Types.

The following rules define the direct supertype relation among the primitive types:

  • double >1 float

  • float >1 long

  • long >1 int

  • int >1 char

  • int >1 short

  • short >1 byte

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
0

Only classes without any explicit constructors at all get a default constructor. For a class that does have one or more constructors explicitly defined, their arity, variable or not, has no bearing. Thus it is reasonably common for a class to have no nullary constructor, and that is in fact the case of your class.

Choosing from among multiple available constructors works the same way as choosing among overloaded methods. First, the available constructors are determined. Then, those that are applicable to the given arguments are identified. Finally, the most specific among the applicable constructors is selected. Details are specified in section 15.12 of JLS10. It is a compile-time error if that process does not result in identifying exactly one constructor.

In your example, both available constructors are applicable to an empty argument list, so it comes down to a question of choosing the most specific. The JLS provides an informal description:

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.

The formal rules revolve around the types of the formal parameters, and account for formal type / subtype relationships among primitive types, with the end result that SomeClass(int...) is more specific than SomeClass(long...) when both are applicable. The former, then, is the one chosen in your example.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157