Перегрузка Java: ссылка на вызов неоднозначную

Рассмотрим следующий пример кода:

public class TestClass {

    public void doSth(String str, String l, Object... objects) {
        System.out.println("A");
    }

    public void doSth(String str, Object... objects) {
        System.out.println("B");
    }

}

Когда я теперь звоню new TestClass().doSth("foo", "bar"), я получаю ожидаемый результат A. Но если я изменил сигнатуру метода первого метода, отвечая параметру l на примитивный тип:

public class TestClass {

    public void doSth(String str, long l, Object... objects) {
        System.out.println("A");
    }

    public void doSth(String str, Object... objects) {
        System.out.println("B");
    }

}

вызов new TestClass().doSth("foo", 2L) приведет к ошибке времени компиляции reference to call ambiguous.

Я подумал об этом один в течение некоторого времени, а также проконсультировался с qaru.site/info/237063/..., но я не смог понять, почему это происходит. По-моему, doSth("foo", 2L) более специфичен для подписи doSth(String string, long l, Object... obj) и должен позволить компилятору также прийти к такому выводу.

Ответ 1

В этом случае автоматическое боксирование вызывает у вас горе. Как ни странно, до этого вы правы - "длинная" версия была бы легко выбрана.

В основном компилятор знает, что он может создать Long от вашего значения, которое, конечно же, является объектом. Поэтому он все еще запутан, так как можно использовать длинную или длинную версию. Один "лучше", чем другой? Возможно, но это довольно тонкая грань.

Ответ 2

В этом состоянии я могу только сообщать о своем наблюдении, а не о том, что именно так говорит WHY, как это происходит.

Сначала, изменив методы на

void doSth(long l) {...}
void doSth(Object o) {...}

избавится от проблемы, т.е. doSth(2L); даст ожидаемый результат.

Переход на один шаг дальше, изменение параметра метода на varargs

void doSth(long... ls) {...}
void doSth(Object... os) {...}

вместе с вызовом doSth(2L); дает ту же ошибку компиляции, о которой сообщает OP.

Мое предложение на этом этапе заключается в том, что инкапсуляция параметра в массив вместе с Autoboxing вызывает хаос. Мои знания о JLS недостаточно прочны, чтобы правильно объяснить это.