Несколько конструкторов с переменными параметрами аргумента
Учитывая эти два конструктора:
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. Вызов метода Преобразование документов.
- Примитивное расширение использует наименьший возможный аргумент метода
- Тип оболочки не может быть расширен на другой тип оболочки
- Вы можете Box от int до Integer и расширить до
Object
но нетLong
- Расширение бьет Бокс, Бокс бьет Вар-аргс.
- Вы можете Box, а затем расширить (An
int
может статьObject
с помощьюInteger
) - Вы не можете расширить, а затем Box (An
int
не может статьLong
) - Вы не можете комбинировать 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...)
когда оба применимы. Первый, то, что выбран в вашем примере.