Указатели функций в Java

Это может быть что-то общее и тривиальное, но у меня, похоже, возникают проблемы с поиском конкретного ответа. В C# существует концепция делегатов, которая сильно связана с идеей указателей функций из C++. Есть ли аналогичная функциональность в Java? Учитывая, что указатели несколько отсутствуют, каков наилучший способ об этом? И для ясности, мы говорим о первом классе.

11 ответов


идиома 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);

вы можете заменить указатель функции с интерфейсом. Допустим, вы хотите запустить коллекцию и сделать что-то с каждым элементом.

public interface IFunction {
  public void execute(Object o);
}

это интерфейс, который мы могли бы передать некоторым, скажем CollectionUtils2.doFunc (коллекция 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++;
    }
});

Вы можете использовать отражение, чтобы сделать это.

передайте в качестве параметра объект и имя метода (в виде строки), а затем вызовите метод. Например:

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");

конечно, проверьте все исключения и добавьте необходимые слепки.


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

однако есть предложения по закрытию (официальное название того, о чем вы говорите) в будущих версиях java - Javaworld есть интересная статья.


Это напоминает Стива Егге исполнение в Царстве существительных. Он в основном утверждает, что Java нужен объект для каждого действия, и поэтому не имеет "только глагола" сущности, такие как указатели функций.


для достижения подобной функциональности вы можете использовать анонимные внутренние классы.

если вы должны были определить интерфейс 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.
    }
}

в 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");
        }
    }
}

Java8 представил лямбды и ссылки на метод. Поэтому, если ваша функция соответствует функционального интерфейса (вы можете создать свой собственный) Вы можете использовать ссылки на метод в этом случае.

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
   }
}

я реализовал поддержку обратного вызова / делегата в Java, используя отражение. Детали и рабочий источник доступны на моем сайте.

Как Это Работает

У нас есть класс принципа с именем Callback с вложенным классом с именем WithParms. API, которому нужен обратный вызов, примет объект обратного вызова в качестве параметра и, если необходимо, создаст обратный вызов.WithParms как переменная метода. Так как очень многие приложения этого объекта будет рекурсивным, это работает очень чисто.

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

для того, чтобы быть threadsafe массив параметров должен существовать однозначно для каждого вызов метода API и для эффективности тот же самый должен использоваться для каждого вызова обратного вызова; мне нужен был второй объект, который был бы дешевым для создания, чтобы связать обратный вызов с массивом параметров для вызова. Но в некоторых сценариях у вызывающего уже был бы массив параметров по другим причинам. По этим двум причинам массив параметров не принадлежал объекту обратного вызова. Также выбор вызова (передача параметров в виде массива или в виде отдельные объекты) принадлежит в руках API, используя обратный вызов, позволяющий ему использовать любой вызов, который лучше всего подходит для его внутренней работы.

вложенный класс WithParms является необязательным и служит двум целям, он содержит массив объектов параметров, необходимый для вызовов обратного вызова, и предоставляет 10 перегруженных методов invoke () (с от 1 до 10 параметрами), которые загружают массив параметров, а затем вызывают цель обратного вызова.


Регистрация закрытие как они были реализованы в библиотеке lambdaj. На самом деле они ведут себя очень похоже на делегатов C#:

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


относительно большинства людей здесь я новичок в 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();

etc.

и звонок

 functionpointer.execute();