Несколько конструкторов с переменными параметрами аргумента

Учитывая эти два конструктора:

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

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

Что происходит, когда создается объект foo?

SomeClass foo = new SomeClass();

Неопределенный конструктор по умолчанию как-то вызывается? Или один из тех конструкторов с пустым массивом называется? Если так, то каков прецедент?

Я провел некоторое базовое тестирование и обнаружил, что если определен конструктор без параметров, он будет вызван. В противном случае, кажется, что неоднозначный называется.

2 ответа

Решение

В соответствии с этим очень хорошим ответом на вопрос "Varargs in overloading method in Java" ниже приведены правила, используемые компилятором Java для выбора сигнатуры метода для вызова. Они основаны на JLS 5.3. Вызов метода Преобразование документов.

  1. Примитивное расширение использует наименьший возможный аргумент метода
  2. Тип оболочки не может быть расширен на другой тип оболочки
  3. Вы можете Box от int до Integer и расширить до Object но нет Long
  4. Расширение бьет Бокс, Бокс бьет Вар-аргс.
  5. Вы можете Box, а затем расширить (An int может стать Object с помощью Integer)
  6. Вы не можете расширить, а затем Box (An int не может стать Long)
  7. Вы не можете комбинировать var-args с расширением или боксом

Поскольку оба конструктора являются var-args (правило 7), компилятор обратится к другим правилам и выберет метод, который использует наименьший тип (правило 1).

Вы можете подтвердить это поведение с помощью следующего кода:

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
}

Точное отношение подтипа между типами примитивов, используемыми в правиле 1, объясняется в JLS 4.10.1. Подтипирование среди примитивных типов.

Следующие правила определяют прямое отношение супертипа среди примитивных типов:

  • double> 1 float

  • float> 1 long

  • long> 1 int

  • int> 1 символ

  • int> 1 short

  • короткий> 1 байт

Только классы без явных конструкторов получают конструктор по умолчанию. Для класса, который имеет один или несколько явно определенных конструкторов, их арность, переменная или нет, не имеет никакого отношения. Таким образом, для класса достаточно часто иметь нулевой конструктор, и это действительно так в вашем классе.

Выбор из нескольких доступных конструкторов работает так же, как выбор из перегруженных методов. Сначала определяются доступные конструкторы. Затем идентифицируются те, которые применимы к данным аргументам. Наконец, выбирается наиболее конкретный среди применимых конструкторов. Подробности указаны в разделе 15.12 JLS10. Это ошибка времени компиляции, если этот процесс не приводит к идентификации только одного конструктора.

В вашем примере оба доступных конструктора применимы к пустому списку аргументов, поэтому вопрос сводится к выбору наиболее конкретного. JLS предоставляет неофициальное описание:

один метод более специфичен, чем другой, если любой вызов, обработанный первым методом, может быть передан другому без ошибки времени компиляции.

Формальные правила вращаются вокруг типов формальных параметров и учитывают формальные отношения типа / подтипа среди примитивных типов с конечным результатом, который SomeClass(int...) более конкретно, чем SomeClass(long...) когда оба применимы. Первый, то, что выбран в вашем примере.

Другие вопросы по тегам