Рассмотрим следующий фрагмент:
public static void main(String[] args) {
Function<String, String> function = String::toUpperCase; //OK
// Comparator<String> comparator = String::toUpperCase; //Compilation error(makes sense, as String.toUpperCase(Locale locale) & String.toUpperCase() are not compatible)
fun(String::toUpperCase); // java: reference to fun is ambiguous
}
public static void fun(Function<String, String> function) { // String apply(String obj)
System.out.println("Function");
}
public static void fun(Comparator<String> comparator) { // int compare(String s1, String s2)
System.out.println("Comparator");
}
Я не понимаю причину ошибки неоднозначности при вызове метода fun(String::toUpperCase).
Поскольку обе перегруженные версии String::toUpperCase сами по себе несовместимы с int compare(String s1, String s2) из класса Comparator, тогда почему компилятор вообще жалуется на неоднозначность?
Я что-то упускаю?




toUpperCase имеет перегрузку, не принимающую параметров, и другую перегрузку, принимающую один параметр (Locale).
Это делает выражение String::toUpperCaseнеточным выражением ссылки на метод. Выражение может относиться либо к перегрузке без аргументов, либо к перегрузке с одним аргументом.
Оба fun определены как «потенциально применимые», в частности, из-за этого пункта:
Выражение ссылки на метод потенциально совместимо с типом функционального интерфейса
Tif, где арность тип функцииTравен n, существует хотя бы одна потенциально применимый метод, когда выражение ссылки на метод нацелено на тип функции с арностью n и верно одно из следующих условий:
- Выражение ссылки на метод имеет форму
ReferenceType :: [TypeArguments] Identifierи по крайней мере одно потенциально применимое метод либо (i) статический и поддерживает арность n, либо (ii) не статический и поддерживает арность n-1.- [не имеющий отношения]
String::toUpperCase потенциально совместим с Function<String, String>, поскольку Function<String, String> имеет арность 1 (принимает один параметр), а toUpperCase нестатичен и имеет перегрузку без аргументов.
String::toUpperCase потенциально совместим с Comparator<String>, поскольку Comparator<String> имеет арность 2, а toUpperCase нестатичен и имеет перегрузку с одним аргументом. Обратите внимание, что на этом шаге вообще не проверяются типы параметров или типы возвращаемых значений. Не имеет значения, что тип параметра — Locale, но на самом деле ожидается String.
Найдя потенциально применимые методы, мы переходим к Определить методы сопоставления арности, применимые путем строгого вызова . Здесь все идет не так. Помните, String::toUpperCase является неточной ссылкой на метод? Это означает, что это не имеет отношения к применимости — компилятор вообще не учитывает ссылку на метод на этом этапе. См. также другой вопрос, который также включает неточное выражение ссылки на метод, вызывающее ошибки разрешения перегрузки.
Таким образом, оба fun применимы при строгом вызове. Следующий шаг — найти наиболее конкретный метод. На этом этапе учитывается подтип, например, String более конкретен, чем Object. Но Comparator<String> не связан с Function<String, String>, поэтому мы не можем найти наиболее конкретный метод, и возникает ошибка.
@RohanJaiswal Нет, что касается этого конкретного шага, они оба применимы, поскольку выражение ссылки на метод не имеет отношения к применимости. т. е. он не участвует в определении того, применима ли перегрузка или нет. Более строгие проверки применяются позже, но компилятор уже столкнулся с ошибкой (а именно, не существует наиболее конкретного метода) до этого момента.
Перефразируя, toUpperCase не применим к фазе strict_invocacy , и он переходит к следующим фазам, т. е. Определить методы сопоставления арности, применимые при свободном вызове и т. д., а затем, наконец, к Выбору Самый конкретный метод, при котором компилятор выдает ошибку.
@RohanJaiswal Просто чтобы быть на одной странице: мы не определяем применимость toUpperCase. Определяем, какие перегрузки fun применимы. И на этапе строгого призыва оба варианта оказываются применимыми. Цитата: «Если m не является универсальным методом, то m применим путем строгого вызова, если для 1 ≤ i ≤ n либо ei совместим в контексте строгого вызова с Fi (§5.3), либо ei не имеет отношения к применимости. " Ссылка на метод не имеет отношения к применимости, поэтому оба fun применимы при строгом вызове, независимо от других факторов.
@RohanJaiswal Обратите внимание, что нет необходимости учитывать, совместимо ли «ei в строгом контексте вызова с Fi», поскольку последнее дизъюнктивное «ei не имеет отношения к применимости» всегда верно. Поскольку оба метода применимы путем строгого вызова, шаги с произвольной и переменной арностью пропускаются. И да, ошибка возникает на этапе «выбора наиболее конкретного метода».
Что касается утверждения «Итак, обе забавы применимы при строгом вызове», вы имели в виду, что вместо этого они неприменимы? Поскольку String::toUpperCase действительно является неточным выражением ссылки на метод.