Ссылка на метод экземпляра

119
15 марта 2021, 14:40

Не могу понять как это работает

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 аргумент. Почему и как это работает?

Answer 1

Нестатические методы неявно принимают аргумент this, указывающий на экземпляр объекта, метод которого вызывается.

Answer 2

Тема: "Передача ссылки на метод произвольного объекта определённого типа".

теперь к вашему коду:

Вот инструкция с вызовом метода, который принимает так называемую "ссылку на метод произвольного объекта определённого типа" - HighTemp::sameTemp

count = counter(weekDayHighs2, HighTemp::sameTemp, new HighTemp(12));

Попробуем представить работу Java, при встрече HighTemp::sameTemp так:

  1. Ищет метод sameTemp в классе HighTemp.

  2. Определяет что он не "static" (если был бы "static", то тут совсем другое поведение);

  3. В найденый метод boolean sameTemp(HighTemp ht2) неявно, в начало, добавляет параметр HighTemp x. В результате сигнатура уже выглядит примерно так: boolean sameTemp(HighTemp x, HighTemp ht2)

  4. Теперь, полученную и слегка "подправленную" (уже с ДВУМЯ параметрами) сигнатуру метода 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) (с одним параметром) а именно:

  1. аргумент vals[i] - выносится из скобок и подставляется вместо f, становясь тем самым "произвольным объектом определённого типа" (из темы). То есть в пункте 3 этот параметр неявно был добавлен, а теперь он "исчезает" (объект vals[i] "вытянули" и он (параметр) больше не нужен!).
  2. 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. Пример рассматриваемого кода из книги Г.Шилдта, как по мне - не самый удачный. Слишком много лишнего, что начинающего только отвлекает от сути изучаемого вопроса.

READ ALSO
Не получается достать jsonArray из json(null)

Не получается достать jsonArray из json(null)

Задача: достать все посты из открытой группы

103
Отладка исходных кодов .Net Framework в Visual Studio

Отладка исходных кодов .Net Framework в Visual Studio

Например, при разработке и в процессе отладке java кода в idea можно проваливаться во внутреннюю реализацию пакетов и классов JDKЕсть ли что-то...

101
Форма обратной связи лишь цифры на клавиатуре

Форма обратной связи лишь цифры на клавиатуре

Интересует такой вопрос есть сайт на Yii2, как сделать так чтобы при клике в форме обратной связи на номер телефона, на клавиатуре телефона...

123
Баг при делении на ноль

Баг при делении на ноль

Начну из далекаПисал калькулятор, и до определённого момента у меня при делении на 0 выводило Error (как и должно было), но почему-то позже это...

82