Несколько конструкторов с переменными параметрами аргумента - PullRequest
0 голосов
/ 09 января 2019

С учетом этих двух конструкторов:

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

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

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

SomeClass foo = new SomeClass();

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

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

Ответы [ 2 ]

0 голосов
/ 09 января 2019

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

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

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

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

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

0 голосов
/ 09 января 2019

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

  1. Примитивное расширение использует наименьший возможный аргумент метода
  2. Тип Wrapper не может быть расширен на другой тип Wrapper
  3. Вы можете Box от int до Integer и расширяться до Object, но не до Long
  4. Расширение бьет Бокс, Бокс бьет Вар-аргс.
  5. Вы можете Box, а затем расширить (int может стать Object через Integer)
  6. Вы не можете расширить, а затем вставить (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 char

  • int> 1 short

  • short> 1 byte

...