Вопрос

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

Это было полезно?

Решение

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

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

Обновить: вышесказанное необходимо в версиях Java, предшествующих Java 8.Теперь у нас есть гораздо более приятные альтернативы, а именно лямбды:

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

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 такого понятия нет.Вам нужно будет обернуть вашу функцию в какой-либо объект и передать ссылку на этот объект, чтобы передать ссылку на метод этого объекта.

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

Пример:

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 с использованием отражения.Подробная информация и рабочий источник приведены ниже доступно на моем веб-сайте.

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

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

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

Чтобы быть потокобезопасным, массив параметров должен существовать уникально для каждого вызова метода 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();

и т.д.

и позвони по

 functionpointer.execute();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top