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

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

 Steven05 июн. 2014 г., 10:30
Java 8method references это именно то, что вы просите.this::myMethod семантически то же самое, что создание лямбдыparamA, paramB -> this.myMethod(paramA, paramB).
 nawfal05 июл. 2014 г., 09:19
 FrustratedWithFormsDesigner06 мая 2014 г., 21:51
Java 8 имеет лямбда-выражения:docs.oracle.com/javase/tutorial/java/javaOO/… Вы можете проверить это. Не совсем указатель на функцию, но все еще может быть более полезным.
 Newtopian02 июл. 2009 г., 12:58
Мне просто любопытно, почему вы хотели бы, чтобы слушатели или другие конструкции ООП выполняли ту же задачу, сохраняя при этом свою объектную природу. Я имею в виду, что я понимаю необходимость функциональности, предлагаемой концепцией, просто для того, чтобы ее можно было достичь с помощью простого объекта ... если, конечно, я что-то упустил, отсюда мой вопрос! :-)
 Steven05 июн. 2014 г., 10:23
Ссылки на методы Java 8 - это именно то, что вы просите.

Ответы на вопрос(11)

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 нуждается в объекте для каждого действия, и, следовательно, не имеет «только для глагола» сущности, такие как указатели на функции.

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

How It Works

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

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

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

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

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

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++;
    }
});
 02 июл. 2009 г., 13:14
Вы можете добавить к этому дженерики ...
 08 нояб. 2010 г., 02:14
Очень ясно и кратко

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

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

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

 Ben Lakey02 июл. 2009 г., 11:28
Интересно - спасибо за информацию.

Проверьте замыкания, как они были реализованы в библиотеке 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();

и т.п.

и позвонить по

 functionpointer.execute();
Решение Вопроса

Идиома Java для функциональности, подобной указателю на функцию, является анонимным классом, реализующим интерфейс, например,

Collections.sort(list, new Comparator<MyClass>(){
    public int compare(MyClass a, MyClass b)
    {
        // compare objects
    }
});

Update: вышеупомянутое необходимо в версиях Java до Java 8. Теперь у нас есть много более хороших альтернатив, а именно лямбда-выражения:

list.sort((a, b) -> a.isGreaterThan(b));

и ссылки на методы:

list.sort(MyClass::isGreaterThan);
 17 мая 2012 г., 04:26
Да, я на самом деле буду использовать указатели на функции C над грубыми классами-обертками в любой день
 25 июн. 2014 г., 11:42
Java 8 имеет лучший синтаксис для этого.
 10 июн. 2011 г., 16:06
@zneak, @Raedwald: Вы можете сделать это в C, передав указатель на пользовательские данные (например, struct). (и может инкапсулировать его с каждым новым уровнем косвенной обратного вызова). Это на самом деле довольно чисто.
 13 янв. 2011 г., 22:41
Стратегия дизайна шаблона. Не так страшно, как указатель на функцию C или C ++, если вы хотите, чтобы функция использовала некоторые неглобальные данные, которые не предоставлены в качестве аргумента функции.
 02 мар. 2011 г., 05:48
@Raedwald C ++ имеет функторы, а C ++ 0x имеет замыкания и лямбды, построенные поверх функторов. Это даже имеетstd::bind, который привязывает параметры к функциям и возвращает вызываемый объект. Я не могу защищать C на этих основаниях, но C ++ действительноis лучше чем Java для этого.

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

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

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

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

 05 авг. 2013 г., 14:34
Отражение не является правильным ответом ни на что, кроме как "Как написать медленный хитрый Java-код" : D
 18 июн. 2013 г., 19:06
Это 1. уродливо и 2. медленно. Но все же правильный ответ. ;)
 16 апр. 2014 г., 20:48
@zoquete .. Я просматривал этот пост, у меня были сомнения .. поэтому в вашем подходе, если я получу доступ к переменной "Описание", функция будет вызываться каждый раз, когда к переменной обращаются ??
 09 апр. 2014 г., 08:50
Это может быть "некрасиво" и медленно, но я считаю, что рефлексия позволяет делать вещи, которые не может сделать решение на основе интерфейса в принятом ответе (если я не ошибаюсь), а именно вызывать различные методы одного и того же объекта в пределах одной и той же части кода.

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

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

Ваш ответ на вопрос