Я ищу способ передать метод по ссылке. Я понимаю, что Java не передает методы в качестве параметров, однако я хотел бы получить альтернативу.
Мне сказали, что интерфейсы - это альтернатива передаче методов в качестве параметров, но я не понимаю, как интерфейс может действовать как метод по ссылке. Если я правильно понимаю, интерфейс - это просто абстрактный набор методов, которые не определены. Я не хочу отправлять интерфейс, который нужно определять каждый раз, потому что несколько разных методов могут вызывать один и тот же метод с одинаковыми параметрами.
То, что я хотел бы сделать, это что-то вроде этого:
public void setAllComponents(Component[] myComponentArray, Method myMethod) {
for (Component leaf : myComponentArray) {
if (leaf instanceof Container) { //recursive call if Container
Container node = (Container) leaf;
setAllComponents(node.getComponents(), myMethod);
} //end if node
myMethod(leaf);
} //end looping through components
}
вызывается, например:
setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
Ответы:
Изменить : начиная с Java 8 лямбда-выражения являются хорошим решением, как указали другие ответы . Ответ ниже был написан для Java 7 и более ранних версий ...
Посмотрите на шаблон команды .
Редактировать: как отмечает Пит Киркхэм , есть еще один способ сделать это с помощью посетителя . Подход на основе посетителей немного более сложен - все ваши узлы должны быть осведомлены о посетителях с помощью
acceptVisitor()
метода, но если вам нужно пройти по более сложному графу объектов, стоит изучить его.источник
В Java 8 теперь вы можете легче передавать метод, используя лямбда-выражения и ссылки на методы . Во-первых, немного предыстории: функциональный интерфейс - это интерфейс, который имеет один и только один абстрактный метод, хотя он может содержать любое количество стандартных методов (новых в Java 8) и статических методов. Лямбда-выражение может быстро реализовать абстрактный метод без всего лишнего синтаксиса, необходимого, если вы не используете лямбда-выражение.
Без лямбда-выражений:
С лямбда-выражениями:
Вот выдержка из учебника Java по лямбда-выражениям :
Вот как вы можете «передать метод» с помощью лямбда-выражения:
Класс
C
может быть сокращен еще немного, используя ссылки на методы, например, так:источник
::
Оператор), не имеет значения, что такое A.a.changeThing(component)
может быть изменен на любой оператор или блок кода, который вы хотите, если он возвращает void.Используйте
java.lang.reflect.Method
объект и позвонитеinvoke
источник
Начиная с Java 8 есть
Function<T, R>
интерфейс ( документы ), который имеет методВы можете использовать его для передачи функций в качестве параметров другим функциям. T - тип ввода функции, R - тип возврата.
В вашем примере вам нужно передать функцию, которая принимает
Component
тип в качестве ввода и ничего не возвращает -Void
. В этом случаеFunction<T, R>
не лучший выбор, так как нет автобокса типа Void. Интерфейс, который вы ищете, называетсяConsumer<T>
( docs ) с методомЭто будет выглядеть так:
И вы бы назвали это, используя ссылки на метод:
Предполагая, что вы определили методы changeColor () и changeSize () в одном классе.
Если ваш метод принимает более одного параметра, вы можете использовать
BiFunction<T, U, R>
- T и U - типы входных параметров, а R - тип возвращаемых. Также естьBiConsumer<T, U>
(два аргумента, нет возвращаемого типа). К сожалению, для 3 и более входных параметров вы должны создать интерфейс самостоятельно. Например:источник
Сначала определите интерфейс с методом, который вы хотите передать в качестве параметра
Реализуйте класс с помощью метода
// вызывать так
Это позволяет вам передавать cmd в качестве параметра и вызывать вызов метода, определенный в интерфейсе
источник
Хотя это еще не относится к Java 7 и ниже, я считаю, что мы должны смотреть в будущее и, по крайней мере, признать изменения, которые появятся в новых версиях, таких как Java 8.
А именно, эта новая версия приносит лямбды и ссылки на методы в Java (вместе с новыми API , которые являются еще одним допустимым решением этой проблемы. Хотя им все еще требуется интерфейс, новые объекты не создаются, и дополнительные файлы классов не должны загрязнять выходные каталоги из-за различных обработка JVM.
Оба варианта (лямбда и ссылка на метод) требуют интерфейса, доступного для одного метода, чья сигнатура используется:
Имена методов не будут иметь значения с этого момента. Там, где принимается лямбда, также указывается метод. Например, чтобы использовать нашу подпись здесь:
Это простой вызов интерфейса до тех пор, пока не будет принята лямбда 1 :
Это выведет:
Ссылки на метод похожи. Дано:
и главное:
выход будет
real static method
. Ссылки на методы могут быть статическими, экземплярами, нестатическими с произвольными экземплярами и даже конструкторами . Для конструктораClassName::new
будет использоваться что-то похожее .1 Это не считается лямбда, поскольку имеет побочные эффекты. Это, однако, иллюстрирует использование одного более простым для визуализации способом.
источник
В прошлый раз, когда я проверял, Java не может делать то, что вы хотите; Вы должны использовать «обходные пути», чтобы обойти такие ограничения. Насколько я понимаю, интерфейсы - это альтернатива, но не очень хорошая альтернатива. Возможно, тот, кто сказал вам, что это означает что-то вроде этого:
Который вы бы затем вызывать с:
источник
Если вам не нужны эти методы для возврата чего-либо, вы можете заставить их возвращать Runnable объекты.
Тогда используйте это как:
источник
Я не нашел достаточно четкого примера для меня, как использовать
java.util.function.Function
простой метод в качестве функции параметра. Вот простой пример:В основном у вас есть
Foo
объект с конструктором по умолчанию. Объект,method
который будет вызываться как параметр изparametrisedMethod
типаFunction<String, Foo>
.Function<String, Foo>
означает, что функция принимает вString
качестве параметра и возвращает aFoo
.Foo::Method
Соответствуют лямбда какx -> Foo.method(x);
parametrisedMethod(Foo::method)
можно рассматривать какx -> parametrisedMethod(Foo.method(x))
.apply("from a method")
основном делатьparametrisedMethod(Foo.method("from a method"))
Который затем вернется в выводе:
Пример должен работать как есть, затем вы можете попробовать более сложные вещи из приведенных выше ответов с различными классами и интерфейсами.
источник
В Java есть механизм для передачи имени и его вызова. Это часть механизма отражения. Ваша функция должна принимать дополнительный параметр класса Method.
источник
Я не эксперт по Java, но я решаю вашу проблему следующим образом:
Я определяю параметр в моем специальном интерфейсе
Наконец, я реализую метод getSearchText при вызове метода initialize .
источник
Используйте шаблон Observer (иногда его также называют шаблоном Listener):
new ComponentDelegate()...
объявляет анонимный тип, реализующий интерфейс.источник
Вот основной пример:
Вывод:
источник
Я не нашел здесь никакого решения, которое бы показывало, как передать метод с привязанными к нему параметрами в качестве параметра метода. Ниже приведен пример того, как вы можете передать метод со значениями параметров, уже привязанными к нему.
Другой пример показывает, как передать метод, который на самом деле возвращает что-то
источник
Пример решения с отражением, переданный метод должен быть публичным
источник
Я ценю ответы выше, но я смог добиться того же поведения, используя метод ниже; идея заимствована из обратных вызовов Javascript. Я открыт для исправления, хотя пока все хорошо (в производстве).
Идея состоит в том, чтобы использовать тип возвращаемого значения функции в сигнатуре, что означает, что yield должен быть статическим.
Ниже приведена функция, которая запускает процесс с таймаутом.
источник