Я могу относиться к вашему замешательству.
У нас есть метод Comparator
, который объявляет два параметра
int compare(T o1, T o2);
и у нас есть метод Integer
, который принимает один параметр
int compareTo(Integer anotherInteger)
Как, черт возьми, Integer::compareTo
разрешается в Comparator
экземпляр?
Когда ссылка на метод указывает на метод экземпляра , анализатор может искать методы с аргументом n-1
(n
- это ожидаемое количество параметров).
Вот выдержка из JLS о том, как определяются применимые методы. Я опущу первую часть о разборе выражения, предшествующего токену ::
.
Во-вторых, для заданного типа функции с параметрами n
идентифицируется набор потенциально применимых методов:
Если выражение ссылки на метод имеет вид ReferenceType :: [TypeArguments] Identifier
, то потенциально применимыми методами являются:
методы-члены типа для поиска, который был бы потенциально применим (§15.12.2.1) для вызова метода, который называет Идентификатор, имеет арность n, имеет аргументы типа TypeArguments и появляется в том же классе, что и выражение ссылки на метод; плюс
методы-члены типа для поиска, которые потенциально могут быть применимы для вызова метода, который именует Identifier
, имеет арность n-1, имеет аргументы типа TypeArguments и появляется в том же классе, что и справочное выражение метода .
Рассматриваются две разные арности, n
и n-1
, чтобы учесть возможность того, что эта форма ссылается либо на статический метод, либо на метод экземпляра.
...
Ссылочное выражение метода в форме ReferenceType :: [TypeArguments] Identifier
можно интерпретировать по-разному. Если Identifier
относится к методу экземпляра, то неявное лямбда-выражение имеет дополнительный параметр по сравнению с тем, если Identifier
относится к статическому методу.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
Если бы мы должны были написать неявное лямбда-выражение из ссылки на этот метод, первый (неявный) параметр был бы экземпляром для вызова метода, а второй (явный) параметр был бы аргументом для передачи в метод.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Обратите внимание, что ссылка на метод отличается от лямбда-выражения, хотя первое может быть легко преобразовано во второе. Лямбда-выражение должно быть desugared в новом методе, в то время как ссылка на метод обычно требует только загрузки соответствующего константного дескриптора метода.
Integer::compareTo
реализует Comparable
интерфейс - не Comparator
.
Integer::compareTo
как выражение не реализует никакого интерфейса. Тем не менее, он может ссылаться на / представлять различные функциональные типы, одним из которых является Comparator<Integer>
.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;