перегрузка с расширением и боксом - PullRequest
5 голосов
/ 07 февраля 2011
public void add(long... x){}
public void add(Integer... x){}

add(2);

это приводит к ошибке ... почему перекрытие не выполняется как с расширением, так и с боксом?

но перегрузка без vararg работает нормально

public void add(long x){}
    public void add(Integer x){}

    add(2);

здесь будет добавлено add (long x), которое расширяет возможности бокса ... почему бы не использовать ту же концепцию var arguments

Ответы [ 2 ]

4 голосов
/ 07 февраля 2011

Компилятор Java выполняет три попытки выбрать подходящую перегрузку метода ( JLS §15.12.2.1 ):

  • Фаза 1: определение подходящих методов арности, применимых подтипом
    (возможные преобразования в бокс и методы с переменными игнорируются)

  • Этап 2. Определение подходящих методов арности, применимых методом Преобразование вызовов
    (учитывает преобразование бокса, но игнорирует методы с переменными)

  • Этап 3: определение применимых методов переменной арности
    (исследует все возможности)

Итак, с вашими примерами это работает следующим образом:

  • Без переменных: add(long x) идентифицируется как единственный применимый метод на 1-й фазе (этот метод применим посредством подтипов, поскольку int является подтипом long, §JLS 4.10.1 ), поэтому следующие этапы не выполняются.

  • С varargs: алгоритм разрешения перегрузки переходит к фазе 3, где оба метода определяются как применимые, и компилятор не может выбрать наиболее конкретный из них (выбор наиболее конкретного метода - еще один сложный алгоритм), поэтому он сообщает о неоднозначности.

Смотри также:

2 голосов
/ 07 февраля 2011

потому что это неоднозначно .

2 может быть Integer, а также long и может быть разрешено для обоих.вы запутали компилятора, кого вызывать:)


5.12.2.2 Выберите наиболее специфичный метод

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

Точное определение заключается в следующем.Пусть m будет именем и предположим, что есть два объявления методов с именем m, каждое из которых имеет n параметров.Предположим, что одно объявление появляется внутри класса или интерфейса T и что типами параметров являются T1,.,,Tn;кроме того, предположим, что другое объявление появляется внутри класса или интерфейса U и что типами параметров являются U1,.,,Un.Тогда метод m, объявленный в T, более специфичен, чем метод m, объявленный в U, в том и только в том случае, если выполняются оба следующих условия:

T можно преобразовать в U путем преобразования вызова метода.Tj может быть преобразовано в Uj преобразованием вызова метода для всех j от 1 до n.Считается, что метод максимально специфичен для вызова метода, если он применим и доступен, и нет другого применимого и доступного метода, более специфичного.Если существует ровно один максимально специфический метод, то это фактически самый специфический метод;он обязательно более конкретен, чем любой другой метод, который применим и доступен.Затем он подвергается некоторым дополнительным проверкам во время компиляции, как описано в §15.12.3.

Возможно, что ни один метод не является наиболее конкретным, поскольку существует два или более максимально специфических метода.В этом случае:

Если все максимально специфические методы имеют одинаковую сигнатуру, то: Если один из максимально специфических методов не объявлен как абстрактный, это наиболее специфический метод.В противном случае все максимально специфические методы обязательно объявляются абстрактными.Наиболее специфический метод выбирается произвольно среди максимально специфических методов.Однако считается, что наиболее конкретный метод вызывает выбрасываемое исключение, если и только если это исключение объявлено в предложениях throws каждого из максимально определенных методов.В противном случае мы говорим, что вызов метода неоднозначен, и возникает ошибка времени компиляции.

15.12.2.3 Пример: Перегрузка неоднозначности

Consider the example:
class Point { int x, y; }
class ColoredPoint extends Point { int color; }

class Test {
    static void test(ColoredPoint p, Point q) {
        System.out.println("(ColoredPoint, Point)");
    }
    static void test(Point p, ColoredPoint q) {
        System.out.println("(Point, ColoredPoint)");
    }
    public static void main(String[] args) {
        ColoredPoint cp = new ColoredPoint();
        test(cp, cp);                                           // compile-time error
    }
}

Этот пример выдает ошибку во время компиляции.Проблема в том, что есть два объявления теста, которые применимы и доступны, и ни одно из них не является более конкретным, чем другое.Поэтому вызов метода неоднозначен.Если добавить третье определение теста:

static void test(ColoredPoint p, ColoredPoint q) {
    System.out.println("(ColoredPoint, ColoredPoint)");
}

, то оно будет более конкретным, чем два других, и вызов метода больше не будет неоднозначным.

...