Подтвердить что ты не робот

Почему не ссылки на методы singleton?

В Java следующий код возвращает false для обоих запросов. Зачем? Разве не было бы проще, чтобы ссылки на методы были одноточечными? Это, безусловно, упростило бы прикрепление и отключение слушателей. Поскольку вам нужно сохранить константу для любой ссылки на метод, которая должна быть проверена на эквивалентность, вы не можете просто использовать оператор ссылки метода в каждом необходимом месте.

public class Main {

    public Main() {
        // TODO Auto-generated constructor stub
    }

    public void doStuff() {

    }

    public static void main(String[] args) {
        Main main = new Main();
        Runnable thing1 = main::doStuff;
        Runnable thing2 = main::doStuff;
        System.out.println(thing1 == thing2); // false
        System.out.println(thing1.equals(thing2)); // false
    }

}
4b9b3361

Ответ 1

Например, методы, я не думаю, что было бы целесообразно кэшировать их. Вам нужно будет кэшировать один метод на экземпляр... что означало бы либо дополнительное поле внутри класса, связанного с этим методом, - по одному на общедоступный метод, предположительно, потому что методы можно было ссылать извне класса или кэшировать в пределах пользователя ссылки на метод, и в этом случае вам понадобится какой-то кеш для каждого экземпляра.

Я думаю, что имеет смысл ссылаться на ссылки на статические методы, которые будут кэшироваться, потому что они будут одинаковыми навсегда. Однако для кэширования фактического Runnable вам понадобится кеш для каждого типа, на который он нацелился. Например:

public interface NotRunnable {
    void foo();
}

Runnable thing1 = Main::doStuff; // After making doStuff static
NotRunnable thing2 = Main::doStuff;

Должны ли быть thing1 и thing2 здесь? Как компилятор знает, какой тип создать, если так? Он может создавать два экземпляра здесь и кэшировать их отдельно - и всегда кэшировать в точке использования, а не в точке объявления метода. (В вашем примере есть тот же класс, объявляющий метод и ссылающийся на него, что является очень особенным случаем. Вы должны рассмотреть более общий случай, когда они разные > )

JLS позволяет кэшировать ссылки на методы. Из раздел 15.13.3:

Далее, присваивается и инициализируется либо новый экземпляр класса со следующими свойствами, либо ссылается на существующий экземпляр класса со следующими свойствами.

... но даже для статических методов кажется, что javac не выполняет кэширование на данный момент.

Ответ 2

В этом простом случае вы можете сделать то, что вы предлагаете, создавая дополнительные статические или экземплярные поля, если это необходимо, более сложными, если лямбда относится к объектам, однако цель состоит в том, чтобы вывести эти экземпляры из существования, например.

List<String> list = ....
list.stream().filter(s -> !s.isEmpty()).forEach(System.out::println);

должен быть таким же эффективным (даже создавая больше объектов, чем)

for (String s : list)
    if(!s.isEmpty())
         System.out.println(s);

Он может устранить объекты путем вложения кода потока и использования анализа эвакуации, чтобы удалить необходимость создания объектов в первую очередь.

По этой причине мало внимания уделяется внедрению equals(), hashCode() или toString(), доступ к ним через отражение для замыканий. AFAIK, это преднамеренно, чтобы избежать использования объектов способами, которые не предназначены.

Ответ 3

Для создания методов одиночные игры потребуется синхронизировать получение ссылки на них. Это дает большие накладные расходы для такой простой операции с непредсказуемым результатом. Другое решение - создать объект для каждого метода при загрузке классов, но это приводит к множеству избыточных объектов, потому что только несколько методов требуют ссылки. Я думаю, что синхронизация является основной проблемой.