Какова ближайшая замена для указателя функции в Java?

Указатель NULL - это тот, который указывает на никуда. Когда вы разыскиваете указатель p, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p является нулевым указателем, местоположение, хранящееся в p, является nowhere, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception.

В общем, это потому, что что-то не было правильно инициализировано.

299
задан Bill the Lizard 9 July 2012 в 05:47
поделиться

11 ответов

Анонимный внутренний класс

Говорит, что Вы хотите передать функцию в с String параметрический усилитель, который возвращается int.
Первый необходимо определить интерфейс с функцией как ее единственный участник, если Вы не можете снова использовать существующий.

interface StringFunction {
    int func(String param);
}

метод А, который берет указатель, просто принял бы StringFunction экземпляр как так: [как 1111]

public void takingMethod(StringFunction sf) {
   int i = sf.func("my string");
   // do whatever ...
}

И назвали бы так:

ref.takingMethod(new StringFunction() {
    public int func(String param) {
        // body
    }
});

РЕДАКТИРОВАНИЕ: В Java 8, Вы могли назвать его с лямбда-выражением:

ref.takingMethod(param -> bodyExpression);
269
ответ дан Mateen Ulhaq 23 November 2019 в 01:29
поделиться

Походит на стратегическую модель мне. Проверьте шаблоны Java fluffycat.com.

4
ответ дан Dennis S 23 November 2019 в 01:29
поделиться

Можно также быть интересно слышать о работе, продолжающейся для Java 7, включающего закрытия:

What’s текущее состояние закрытий в Java?

http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures

12
ответ дан Community 23 November 2019 в 01:29
поделиться

Необходимо создать интерфейс, который обеспечивает функцию (функции), которую Вы хотите раздать. например:

/**
 * A simple interface to wrap up a function of one argument.
 * 
 * @author rcreswick
 *
 */
public interface Function1<S, T> {

   /**
    * Evaluates this function on it's arguments.
    * 
    * @param a The first argument.
    * @return The result.
    */
   public S eval(T a);

}

Затем когда необходимо передать функцию, можно реализовать тот интерфейс:

List<Integer> result = CollectionUtilities.map(list,
        new Function1<Integer, Integer>() {
           @Override
           public Integer eval(Integer a) {
              return a * a;
           }
        });

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

   public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn, 
         Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
      Set<K> keySet = new HashSet<K>();
      keySet.addAll(m1.keySet());
      keySet.addAll(m2.keySet());

      results.clear();

      for (K key : keySet) {
         results.put(key, fn.eval(m1.get(key), m2.get(key)));
      }
      return results;
   }

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

24
ответ дан rcreswick 23 November 2019 в 01:29
поделиться

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

пример @sblundy хорош.

32
ответ дан Community 23 November 2019 в 01:29
поделиться

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

13
ответ дан Peter Lawrey 23 November 2019 в 01:29
поделиться

Можно также сделать это (который в некоторых случаях RARE имеет смысл). Проблема (и это - большая проблема), то, что Вы теряете весь typesafety использования класса/интерфейса, и необходимо иметь дело со случаем, где метод не существует.

Это действительно обладает "преимуществом", что можно проигнорировать ограничения доступа и назвать закрытые методы (не показанный в примере, но можно назвать методы, которые компилятор обычно не позволял бы Вам назвать).

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

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Main
{
    public static void main(final String[] argv)
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        final String methodName;
        final Method method;
        final Main   main;

        main = new Main();

        if(argv.length == 0)
        {
            methodName = "foo";
        }
        else
        {
            methodName = "bar";
        }

        method = Main.class.getDeclaredMethod(methodName, int.class);

        main.car(method, 42);
    }

    private void foo(final int x)
    {
        System.out.println("foo: " + x);
    }

    private void bar(final int x)
    {
        System.out.println("bar: " + x);
    }

    private void car(final Method method,
                     final int    val)
        throws IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        method.invoke(this, val);
    }
}
15
ответ дан TofuBeer 23 November 2019 в 01:29
поделиться

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

public enum Operation {
    PLUS {
        public double calc(double a, double b) {
            return a + b;
        }
    },
    TIMES {
        public double calc(double a, double b) {
            return a * b;
        }
    }
     ...

     public abstract double calc(double a, double b);
}

Очевидно, объявление метода стратегии, а также точно один экземпляр каждой реализации все определяются в едином классе / файл.

28
ответ дан javashlook 23 November 2019 в 01:29
поделиться

Ознакомьтесь с lambdaj

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

и, в частности, с его новой функцией закрытия

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

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

3
ответ дан 23 November 2019 в 01:29
поделиться

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

Однажды я узнал себя, почему бы не? У нас есть указатели метода - объект метода. С оптимизацией jit Compilers, рефлексивный вызов действительно не несет огромный штраф производительности. И кроме того, скажем, копируя файл из одного местоположения в другое, стоимость отраженного метода вызывания Pales в незначительность.

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

Проверьте мое решение на основе отражения для обратных вызовов в Java . Бесплатно для любого использования.

4
ответ дан 23 November 2019 в 01:29
поделиться

@ sblundy's ответ отличный, но у анонимных внутренних классов есть два небольших недостатка, главный из которых состоит в том, что они не могут использоваться повторно, а второй - в громоздком синтаксисе.

Приятно то, что его шаблон расширяется до полных классов без каких-либо изменений в основном классе (выполняющем вычисления).

Когда вы создаете экземпляр нового класса, вы можете передавать в этот класс параметры, которые могут действовать как константы в вашем уравнении - поэтому, если один из ваших внутренних классов выглядит так:

f(x,y)=x*y

, но иногда вам нужен такой:

f(x,y)=x*y*2

и, возможно, третье:

f(x,y)=x*y/2

вместо того, чтобы создавать два анонимных внутренних класса или добавлять параметр «сквозной передачи», вы можете создать один АКТУАЛЬНЫЙ класс, который вы создаете как:

InnerFunc f=new InnerFunc(1.0);// for the first
calculateUsing(f);
f=new InnerFunc(2.0);// for the second
calculateUsing(f);
f=new InnerFunc(0.5);// for the third
calculateUsing(f);

Он просто сохранит константу в классе и используйте его в методе, указанном в интерфейсе.

На самом деле, если ЗНАЕТ, что ваша функция не будет сохраняться / повторно использоваться, вы можете сделать это:

InnerFunc f=new InnerFunc(1.0);// for the first
calculateUsing(f);
f.setConstant(2.0);
calculateUsing(f);
f.setConstant(0.5);
calculateUsing(f);

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

На самом деле я публикую это только потому, что меня передергивает всякий раз, когда я слышу анонимный внутренний класс - я видел много избыточного кода, который был «Обязательным», потому что первое, что сделал программист, был анонимным, когда он должен был использовать реальный класс и никогда не пересматривал свое решение.

9
ответ дан 23 November 2019 в 01:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: