Разрешение перегрузки с помощью ссылок на методы и специализаций интерфейса функций для примитивных типов
Допустим, у нас есть класс и перегруженная функция:
public class Main {
static final class A {
}
public static String g(ToIntFunction<? extends A> f) {
return null;
}
public static String g(ToDoubleFunction<? extends A> f) {
return null;
}
}
И я хочу вызвать g со ссылкой на метод функции типа A - > int:
public class Main {
static final class A {
}
public static String g(ToIntFunction<? extends A> f) {
return null;
}
public static String g(ToDoubleFunction<? extends A> f) {
return null;
}
private static int toInt(A x) {
return 2;
}
public static void main(String[] args) {
ToIntFunction<? extends A> f1 = Main::toInt;
ToDoubleFunction<? extends A> f2 = Main::toInt;
g(Main::toInt);
}
}
Это работает с javac, но не с eclipse ecj. Я отправил сообщение об ошибке в ecj, но я не уверен, что это ошибка ecj или javac, и попытался следовать алгоритму разрешения перегрузки, чтобы выяснить это. Я считаю, что код должен быть принят, потому что интуитивно понятно, что ToIntFunction
является лучшим соответствием для toInt
чем ToDoubleFunction
. Однако мое прочтение JLS заключается в том, что он должен быть отклонен, потому что нет никаких оснований для того, чтобы он был более конкретным.
Main::double2int
, поэтому я посмотрел на 15.13.2. Тип ссылки на метод . Он не определяет тип, но определяет, когда тип совместим в разных контекстах:
Ссылка на метод выражение совместимо в контексте присваивания, контекст вызова или контекст приведения с целевым типом T, если T-это функциональный тип интерфейса (§9.8) и выражение соответствует тип функции типа наземной цели, производной от T.
Основными типами являются ToIntFunction<A>
и ToDoubleFunction<A>
. toInt
возвращает int, который является присваиванием, совместимым с double, поэтому я бы заключил, что ссылка на метод совместима с ToIntFunction<? extends A>
и ToDoubleFunction<? extends A>
в контексте вызова. Это может быть проверено путем ассингинга ссылки метода как на ToIntFunction<? extends A>
, так и на ToDoubleFunction<? extends A>
, которая принимается в основной функции.
ToIntFunction
или ToDoubleFunction
более специфична для параметра Main::toInt
объявления времени компиляции A -> int
.
Функциональный интерфейс типа S более специфичен, чем функционал тип интерфейса T для выражения e, если T не является подтипом S и верно одно из следующих значений (где U1 ... Великобритания и R1 являются типы параметров и возвращаемого типа функции захвата С и В1 ... Vk и R2 - типы параметров и возвращаемый тип функции типа T):
...
Если e-точное выражение ссылки на метод (§15.13.1), то i) для все i (1 ≤ i ≤ k), Ui такое же, как Vi, и ii) одно из следующих верно:
R2-пустота.
R1
R1-примитивный тип, R2-ссылочный тип, а время компиляции объявление для ссылки на метод имеет возвращаемый тип, который является примитивный тип.
R1-ссылочный тип, R2-примитивный тип, а время компиляции объявление для ссылки на метод имеет возвращаемый тип, который является ссылочный тип.
Первое условие, очевидно, не совпадает, потому что R1 и R2 не совпадают. пустота.
Два интерфейса ToIntFunction
и ToDoubleFunction
отличаются только типами возвращаемых данных, которые являются примитивными типами double
и int
. Для примитивных типов предложение "R1 double и int
, поэтому этот случай не определяет, какой тип более специфичен.
Кажется, что нет правила для случая, когда два функциональных интерфейса возвращают примитивы и код должен быть отклонен как неоднозначный. Однако javac принимает код, и я ожидал бы, что он это сделает. Поэтому мне интересно, не является ли это упущенной точкой в JLS.
1 ответ:
Для примитивных типов предложение "R1 <:>
Это не так;
double
на самом деле является супертипомint
.Супертипы типа получаются рефлексивными и транзитивными замыкание над прямым отношением супертипа, записанное
S >₁ T
, который является определяется правилами, приведенными ниже в этом разделе. Мы пишемS :> T
, чтобы укажите, что отношение супертипа выполняется междуS
иT
.Следующие правила определяют прямое отношение супертипа между примитивные типы:
double >₁ float
float >₁ long
long >₁ int
Отношениесупертипа , являющееся рефлексивным и транзитивным замыканием прямого отношение супертипа означает, что из
(double >₁ float) ∧ (float >₁ long) ∧ (long >₁ int)
следуетdouble :> int
.