Указатели функций в 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. Они действительно имеют поведение, очень похожее на делегатов С#:

http://code.google.com/p/lambdaj/wiki/Closures

Ответ 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();