Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Анонимный внутренний класс
Говорит, что Вы хотите передать функцию в с 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);
Походит на стратегическую модель мне. Проверьте шаблоны Java fluffycat.com.
Можно также быть интересно слышать о работе, продолжающейся для Java 7, включающего закрытия:
What’s текущее состояние закрытий в Java?
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures
Необходимо создать интерфейс, который обеспечивает функцию (функции), которую Вы хотите раздать. например:
/**
* 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;
}
можно часто использовать Выполнимый вместо собственного интерфейса, если Вы не должны передавать в параметрах, или можно использовать различные другие методы для проведения менее "фиксированного" подсчета параметрического усилителя, но это обычно - согласование с безопасностью типов. (Или можно переопределить конструктора для функционального объекта для передачи в параметрических усилителях того пути.. существует много подходов и некоторой работы лучше при определенных обстоятельствах.)
Для каждого "указателя функции" я создал бы маленькое класс функтора, который реализует Ваше вычисление. Определите интерфейс, который все классы реализуют, и передавать экземпляры тех объектов в Вашу большую функцию. Это - комбинация" шаблон "команда" ", и" стратегическая модель ".
пример @sblundy хорош.
Если у Вас есть всего одна строка, которая отличается, Вы могли добавить параметр, такой как флаг и, если (флаг) оператор, который называет одну строку или другой.
Можно также сделать это (который в некоторых случаях 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);
}
}
Когда существует предопределенное количество различных вычислений, можно сделать в той одной строке, использование перечисления является быстрым, все же ясным способом реализовать стратегическую модель.
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);
}
Очевидно, объявление метода стратегии, а также точно один экземпляр каждой реализации все определяются в едином классе / файл.
Ознакомьтесь с lambdaj
http://code.google.com/p/lambdaj/
и, в частности, с его новой функцией закрытия
http://code.google .com / p / lambdaj / wiki / Closures
, и вы найдете очень удобочитаемый способ определения замыкания или указателя на функцию без создания бессмысленного интерфейса или использования уродливых внутренних классов
Одно из вещей, которые я действительно скучаю, когда программирование в Java - обратные вызовы функций. Одна ситуация, когда потребность в этих условиях представляла себя, была в рекурсически обработке иерархии, где вы хотите выполнить некоторые конкретные действия для каждого предмета. Как ходить в каталоге дерева или обработка структуры данных. Минималистский внутри меня ненавидит, чтобы определить интерфейс, а затем реализацию для каждого конкретного случая.
Однажды я узнал себя, почему бы не? У нас есть указатели метода - объект метода. С оптимизацией jit Compilers, рефлексивный вызов действительно не несет огромный штраф производительности. И кроме того, скажем, копируя файл из одного местоположения в другое, стоимость отраженного метода вызывания Pales в незначительность.
Как я подумал об этом больше, я понял, что обратный вызов в парадигме OOP требует привязки объекта и метода вместе - введите объект обратного вызова.
Проверьте мое решение на основе отражения для обратных вызовов в Java . Бесплатно для любого использования.
@ 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);
Но неизменяемые классы безопаснее - я не могу придумать оправдания, чтобы сделать такой класс изменяемым .
На самом деле я публикую это только потому, что меня передергивает всякий раз, когда я слышу анонимный внутренний класс - я видел много избыточного кода, который был «Обязательным», потому что первое, что сделал программист, был анонимным, когда он должен был использовать реальный класс и никогда не пересматривал свое решение.