Это может быть что-то общее и тривиальное, но мне, кажется, не удается найти конкретный ответ. В С# существует понятие делегатов, которое сильно относится к идее указателей на функции из С++. Есть ли аналогичная функциональность в Java? Учитывая, что указатели несколько отсутствуют, что это лучший способ? И чтобы быть понятным, мы говорим о первом классе здесь.
Указатели функций в Java
Ответ 1
Идиома Java для функционально-указательных функций - это анонимный класс, реализующий интерфейс, например
Collections.sort(list, new Comparator<MyClass>(){
public int compare(MyClass a, MyClass b)
{
// compare objects
}
});
Обновление: вышеуказанное необходимо в версиях Java до Java 8. Теперь у нас есть намного более приятные альтернативы, а именно lambdas:
list.sort((a, b) -> a.isGreaterThan(b));
и ссылки на методы:
list.sort(MyClass::isGreaterThan);
Ответ 2
Вы можете заменить указатель на функцию интерфейсом. Допустим, вы хотите запустить коллекцию и сделать что-то с каждым элементом.
public interface IFunction {
public void execute(Object o);
}
Это интерфейс, который мы могли бы передать некоторым словам CollectionUtils2.doFunc(Collection c, IFunction f).
public static void doFunc(Collection c, IFunction f) {
for (Object o : c) {
f.execute(o);
}
}
В качестве примера скажем, что у нас есть набор чисел, и вы хотели бы добавить 1 к каждому элементу.
CollectionUtils2.doFunc(List numbers, new IFunction() {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
}
});
Ответ 3
Вы можете использовать отражение, чтобы сделать это.
Передайте в качестве параметра объект и имя метода (в виде строки), а затем вызовите метод.
Например:
Object methodCaller(Object theObject, String methodName) {
return theObject.getClass().getMethod(methodName).invoke(theObject);
// Catch the exceptions
}
И затем используйте его, как в:
String theDescription = methodCaller(object1, "toString");
Class theClass = methodCaller(object2, "getClass");
Конечно, проверьте все исключения и добавьте необходимые роли.
Извините, мой плохой английский.
Bye!
Ответ 4
Нет, функции не являются объектами первого класса в java. Вы можете сделать то же самое, внедряя класс обработчика - это то, как обратные вызовы реализованы в Swing и т.д.
Однако существуют предложения по закрытию (официальное название того, о чем вы говорите) в будущих версиях java - Javaworld интересная статья.
Ответ 5
Это напоминает Steve Yegge Выполнение в Королевстве существительных. Он в основном утверждает, что Java требуется объект для каждого действия и, следовательно, не имеет таких только "глагольных" объектов, как указатели на функции.
Ответ 6
Для достижения аналогичной функциональности вы можете использовать анонимные внутренние классы.
Если вы должны определить интерфейс Foo
:
interface Foo {
Object myFunc(Object arg);
}
Создайте метод bar
, который получит в качестве аргумента "указатель функции":
public void bar(Foo foo) {
// .....
Object object = foo.myFunc(argValue);
// .....
}
Наконец, вызовите метод следующим образом:
bar(new Foo() {
public Object myFunc(Object arg) {
// Function code.
}
}
Ответ 7
В Java нет такой вещи. Вам нужно будет обернуть вашу функцию в какой-то объект и передать ссылку на этот объект, чтобы передать ссылку на метод этого объекта.
Синтаксически это можно в определенной степени облегчить, используя анонимные классы, определенные на месте или анонимные классы, определяемые как переменные-члены класса.
Пример:
class MyComponent extends JPanel {
private JButton button;
public MyComponent() {
button = new JButton("click me");
button.addActionListener(buttonAction);
add(button);
}
private ActionListener buttonAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// handle the event...
// note how the handler instance can access
// members of the surrounding class
button.setText("you clicked me");
}
}
}
Ответ 8
Я реализовал поддержку обратного вызова/делегата в Java с использованием отражения. Подробности и рабочий источник доступны на моем сайте.
Как это работает
У нас есть основной класс с именем Callback с вложенным классом с именем WithParms. API, который нуждается в обратном вызове, примет объект Callback как параметр и, если необходимо, создаст Callback.WithParms как переменную метода. Поскольку многие приложения этого объекта будут рекурсивными, это работает очень чисто.
Когда производительность по-прежнему остается для меня первоочередной задачей, я не хотел, чтобы мне требовался создать массив сбрасываемым объектом для хранения параметров для каждого вызова - ведь в большой структуре данных могут быть тысячи элементов, а в сценарий обработки сообщений, мы могли бы обработать тысячи структур данных в секунду.
Для того, чтобы быть потокобезопасным, массив параметров должен существовать уникально для каждого вызова метода API, а для эффективности тот же самый должен использоваться для каждого вызова обратного вызова; Мне понадобился второй объект, который был бы дешевым для создания, чтобы связать обратный вызов с массивом параметров для вызова. Но в некоторых сценариях у invoker уже был массив параметров по другим причинам. По этим двум причинам массив параметров не принадлежал объекту обратного вызова. Также выбор вызова (передача параметров в виде массива или отдельных объектов) принадлежит к API, используя обратный вызов, позволяющий ему использовать любой вызов, наиболее подходящий для его внутренних действий.
Вложенный класс WithParms является необязательным и служит для двух целей: он содержит массив объектов параметров, необходимый для вызовов обратного вызова, и предоставляет 10 перегруженных методов invoke() (с 1 до 10 параметров), которые загружают параметр массив, а затем вызвать цель обратного вызова.
Ответ 9
Java8 представила lambdas и ссылки на методы. Поэтому, если ваша функция соответствует функциональному интерфейсу (вы можете создать свой собственный), вы можете использовать ссылку метода в этом случае.
Java предоставляет набор общих функциональных интерфейсов. тогда как вы можете сделать следующее:
public class Test {
public void test1(Integer i) {}
public void test2(Integer i) {}
public void consumer(Consumer<Integer> a) {
a.accept(10);
}
public void provideConsumer() {
consumer(this::test1); // method reference
consumer(x -> test2(x)); // lambda
}
}
Ответ 10
Проверьте блокировки, как они были реализованы в библиотеке lambdaj. Они действительно имеют поведение, очень похожее на делегатов С#:
Ответ 11
Относительно большинства людей здесь я новичок в java, но, поскольку я не видел подобного предложения, у меня есть другая альтернатива, чтобы предложить. Я не уверен, что это хорошая практика или нет, или даже предложил раньше, и я просто не понял. Мне просто нравится, так как я думаю, что он сам описательный.
/*Just to merge functions in a common name*/
public class CustomFunction{
public CustomFunction(){}
}
/*Actual functions*/
public class Function1 extends CustomFunction{
public Function1(){}
public void execute(){...something here...}
}
public class Function2 extends CustomFunction{
public Function2(){}
public void execute(){...something here...}
}
.....
/*in Main class*/
CustomFunction functionpointer = null;
тогда в зависимости от приложения назначьте
functionpointer = new Function1();
functionpointer = new Function2();
и т.д..
и вызов
functionpointer.execute();