Я полагал, что вывод типа локальной переменной Java 10 (var name = ...;
) будет ответом на эту загадку. Вместо того, чтобы тип переменной назначения предоставлял тип для ссылки на метод, в правой части необходимо было бы полностью указать тип, что потребовало бы параметра типа (::<T>
) в ссылке на метод.
Сначала придумали ворота...
var arraySorter = Arrays::<Double>sort;
... но ссылки на методы сами по себе не определяют тип. Они должны быть преобразованы компилятором в функциональный объект, и компилятор не будет искать известные функциональные интерфейсы в поисках соответствующего типа, даже если он был ровно один.
Следующей мыслью было использовать ссылку на метод в качестве аргумента метода, который возвращает тип на основе аргумента метода.
class Spy {
static <T> Function<T,T> f2(Function<T,T> f) {
return f.andThen(f);
}
static <T> T identity(T t) {
return t;
}
}
Используя это, мы можем создать нашу локальную переменную, передав ссылку на наш метод:
Function<Double,Double> double_identity = f2(Spy::<Double>identity);
Как и ожидалось, мы можем удалить ::<Double>
Function<Double,Double> double_identity = f2(Spy::identity);
Неожиданно, с выводом типа локальной переменной все в порядке.
var double_identity = f2(Spy::identity); // Infers <Object>!
Object obj = null;
double_identity.apply(obj);
Но настоящий сюрприз возникает, когда для его переопределения используется ссылочный тип метода.
var double_identity = f2(Spy::<Double>identity); // Error: Double != Object
Немного поругавшись, я понял, почему. Мы должны применить тип к самому методу f2
:
var double_identity = Spy.<Double>f2(Spy::identity); // Works.
Оглядываясь назад, это имеет некоторый смысл. Тип переменной обычно обеспечивает контекст для внешней функции. Присвоение результата переменной Function<Double,Double>
позволяет компилятору определить тип f2(...)
, который затем передает этот тип в аргументы. С var name = ...
без явного типа доступен только тип Object
, поэтому компилятор выводит Spy.<Object>f2(...)
, а затем определяет, что тип аргумента должен быть Function<Object,Object>
.
К сожалению, кажется, что он не анализирует изнутри, так что Spy::<Double>identity
не приводит к тому, что функция выводится как Spy.<Double>f2(...)
, а переменная - как Function<Double,Double>
. Может Ява 11? Возможно, он слишком сильно сломается и не сможет работать.
Однако это положило конец моим попыткам злоупотребить var name = ...;
, чтобы решить загадку ОП.
Большое спасибо @Eugene за критику моих предыдущих попыток до выпуска Java 10.
person
AJNeufeld
schedule
17.03.2018
FooBar
является производным отFoo
: в Java7:List<Foo> foo = Arrays.asList(new FooBar());
не будет компилироваться, но будет компилироваться в Java8. Java7 нуждается в параметре типа:List<Foo> foo = Arrays.<Foo>asList(new FooBar());
. - person AJNeufeld   schedule 17.03.2018::<T>
. - person fps   schedule 17.03.2018