Не могу понять как это работает
public interface MyFunc<T> {
boolean func(T v1, T v2);
}
public class HighTemp {
private int hTemp;
HighTemp(int ht) {
hTemp = ht;
}
boolean sameTemp(HighTemp ht2) {
return hTemp == ht2.hTemp;
}
boolean lessThanTemp(HighTemp ht2) {
return hTemp < ht2.hTemp;
}
}
public class InctanceMethWithObjectRefDemo {
static <T> int counter(T[] vals, MyFunc<T> f, T v) {
int count = 0;
for(int i=0; i < vals.length; i++)
if(f.func(vals[i], v)) count++;
return count;
}
public static void main(String[] args) {
int count;
HighTemp[] weekDayHighs = { new HighTemp(89), new HighTemp(82),
new HighTemp(90), new HighTemp(89),
new HighTemp(89), new HighTemp(91),
new HighTemp(84), new HighTemp(83)};
count = counter(weekDayHighs, HighTemp::sameTemp, new HighTemp(89));
System.out.println("Дней, когда максимальная температура была 89: " + count);
HighTemp[] weekDayHighs2 = { new HighTemp(32), new HighTemp(12),
new HighTemp(24), new HighTemp(19),
new HighTemp(18), new HighTemp(12),
new HighTemp(-1), new HighTemp(13)};
count = counter(weekDayHighs2, HighTemp::sameTemp, new HighTemp(12));
System.out.println("Дней, когда температура была 12: " + count);
count = counter(weekDayHighs, HighTemp::lessThanTemp, new HighTemp(89));
System.out.println("Дней, когда температура была меньше 89: " + count);
count = counter(weekDayHighs2, HighTemp::lessThanTemp, new HighTemp(19));
System.out.println("Дней, когда температура была меньше 19: " + count);
}
}
а именно это f.func(vals[i], v). Почему в f.func(vals[i], v) передается 2 аргумента, когда в переменную f передается ссылка на метод sameTemp, который принимает 1 аргумент. Почему и как это работает?
Нестатические методы неявно принимают аргумент this
, указывающий на экземпляр объекта, метод которого вызывается.
Тема: "Передача ссылки на метод произвольного объекта определённого типа".
теперь к вашему коду:
Вот инструкция с вызовом метода, который принимает так называемую "ссылку на метод произвольного объекта определённого типа" - HighTemp::sameTemp
count = counter(weekDayHighs2, HighTemp::sameTemp, new HighTemp(12));
Попробуем представить работу Java, при встрече HighTemp::sameTemp так:
Ищет метод sameTemp в классе HighTemp.
Определяет что он не "static" (если был бы "static", то тут совсем другое поведение);
В найденый метод boolean sameTemp(HighTemp ht2)
неявно, в начало, добавляет параметр HighTemp x
. В результате сигнатура уже выглядит примерно так: boolean sameTemp(HighTemp x, HighTemp ht2)
Теперь, полученную и слегка "подправленную" (уже с ДВУМЯ параметрами) сигнатуру
метода sameTemp boolean sameTemp(HighTemp x, HighTemp ht2)
сравнивает с сигнатурой метода функционального интерфейса MyFunc boolean func(T v1, T v2)
, у которой тоже ДВА параметра одинакового типа, и такое же возвращаемое значение.
С этим всё, надеюсь понятно.
далее, когда Java встречает это варажение (в методе counter):
f.func(vals[i], v)
перед тем как его исполнить, происходит мэджик следующее:
метод интерфейса boolean func(T v1, T v2)
(с двумя параметрами) трансформируется в наш изначальный метод sameTemp boolean sameTemp(HighTemp ht2)
(с одним параметром) а именно:
vals[i]
- выносится из скобок и подставляется вместо f
, становясь тем самым "произвольным объектом определённого типа" (из темы). То есть в пункте 3 этот параметр неявно был добавлен, а теперь он "исчезает" (объект vals[i]
"вытянули" и он (параметр) больше не нужен!).func(v)
c оставшимся одним параметром, становится sameTemp(v)
в итоге получаем, что Java исполняя это:
f.func(vals[i], v)
фактически исполняет это:
vals[i].sameTemp(v)
Важно понять, что метод sameTemp(HighTemp ht2)
может иметь хоть 5 параметров!
В любом случае (по приведённой схеме в п.п.3 и далее) в начало списка параметров будет неявно добавлен шестой параметр (в нашем случае - типа HighTemp), чтобы в дальнейшем получить в этом параметре "произвольный" объект, извлечь его, и использовать как тот самый "произвольный объект" метод которого Java и будет вызывать.
(если у метода sameTemp было бы 5 параметров, то тогда у метода функционального интерфейса должно быть их 6. Первый из которых должен быть обязательно "определённого типа" (под "определённым типом" подразумевается класс, с методом "произвольного экземпляра" которого мы хотим ассоциировать метод интерфейса))
Примерно поняв, как это работает, название самой темы: - "Передача ссылки на метод произвольного объекта определённого типа" должна звучать слегка дружелюбнее).
P.S. Пример рассматриваемого кода из книги Г.Шилдта, как по мне - не самый удачный. Слишком много лишнего, что начинающего только отвлекает от сути изучаемого вопроса.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Например, при разработке и в процессе отладке java кода в idea можно проваливаться во внутреннюю реализацию пакетов и классов JDKЕсть ли что-то...
Интересует такой вопрос есть сайт на Yii2, как сделать так чтобы при клике в форме обратной связи на номер телефона, на клавиатуре телефона...
Начну из далекаПисал калькулятор, и до определённого момента у меня при делении на 0 выводило Error (как и должно было), но почему-то позже это...