Интуитивно мы уже вкладываем много динамизма в функции (методы), которые мы обычно пишем: мы используем все виды условных ветвлений и циклов. Если вы можете каким-то образом ограничить то, что можно сделать, вы можете построить свою функцию, используя эти простые конструкции.
Тем не менее, неясно, из вашего вопроса, что именно динамичность вы ожидаете:
- Фактическое кодирование Java
- оценки простых выражений, как
1+2*(4-8)
- или какой-либо другой сценарий, как конструкт вы хотите, чтобы разобрать и оценить
Для реального Java-кодирования я бы предложил реализовать некоторую абстракцию с использованием пары API/SPI. SPI - это интерфейс поставщика услуг или абстракция, которая позволяет другим предоставлять готовые и скомпилированные классы в качестве расширения. Я считаю, OSGI предоставляет стандартный способ сделать это.
Для оценки выражений существует множество сторонних библиотек. Я разработал один, но не упомянул, так как есть много других. На этой доске нет цели выдвинуть один инструмент над заказом. Вы также можете рассмотреть Nashorn, который является механизмом JavaScript.
Чтобы разрешить сценарии, я бы предложил придерживаться javascript и использовать Nashorn. Java позволяет создавать плагины и фактически позволяет добавлять дополнительные скриптовые двигатели как часть JSR-223.
[UPDATE]
Исходя из ваших уточнений и ваш пример, да нам нужно будет использовать некоторый тип отражения.
В вашем случае вы хотите лениво решить, к какому классу или экземпляру вы собираетесь применить метод. Это ограничивает меня решением, как показано ниже, однако я сделал это еще на один шаг, оптимизируя реализацию для одного случая: где класс экземпляров функциональных объектов будет применен или может быть определен заранее.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;
public class Play {
public int hello() {
return 5;
}
static public int byebye() {
return -1;
}
public static class ExtendedPlay extends Play {
@Override
public int hello() {
return 10;
}
}
private static <T> Function<T,Integer> getFunction(Class<T> clazz,String method) throws NoSuchMethodException {
Method m = clazz.getDeclaredMethod(method);
return (o)->{
try {
return ((Integer)m.invoke(o));
} catch (IllegalAccessException | InvocationTargetException ex) {
// Just hope and pray this will be all ok!
}
return 0;
};
}
private static <T> Function<Class<T>,Integer> getStaticFunction(Class<T> clazz,String method) throws NoSuchMethodException {
Method m = clazz.getDeclaredMethod(method);
return (o)->{
try {
return ((Integer)m.invoke(o));
} catch (IllegalAccessException | InvocationTargetException ex) {
// Just hope and pray this will be all ok!
}
return 0;
};
}
private static Function<Object,Integer> getFunction(String method) {
return (o)->{
try {
Method m;
if (o instanceof Class) // For static methods
m = ((Class)o).getDeclaredMethod(method);
else // For instance methods
m = o.getClass().getDeclaredMethod(method);
return ((Integer)m.invoke(o));
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
// Just hope and pray this will be all ok!
}
return 0;
};
}
public static void main(String args[]) throws NoSuchMethodException {
// Little quicker because class type and Method instance can be resolved before multiple executions.
// Method is cached and has better compile-time type checking, but requires extra paramter.
Function<Play,Integer> f1 = getFunction(Play.class,"hello");
Function<Class<Play>,Integer> f2 = getStaticFunction(Play.class,"byebye");
// Little slower, because method instance has to be resolved for each subsequent call
// of the dereferenced Function Object. Slower but use is simpler: one less parameter, and works for
// both static and instance methods.
Function<Object,Integer> f3 = getFunction("hello");
System.out.println("Value1 is: "+f1.apply(new ExtendedPlay()));
System.out.println("Value2 is: "+f2.apply(Play.class));
System.out.println("Value3 is: "+f3.apply(new Play()));
}
}
Обратите внимание, что я принял решение таким образом, чтобы оно работало как с статическими методами, так и с экземплярами.
'Function' - это интерфейс ... – immibis
ОК, я хочу создать ссылку на метод, который может быть сохранен в переменной' Function'. –
Почему вы хотите это сделать? –