在运行时构造函数

Construct a Function at runtime

是否可以使用反射从 String 创建一个 java.util.function.Function?我似乎无法找到一种方法来做到这一点,因为 Function.

没有构造函数

所以说我有这个方法:

public Integer hello() {
    return 5;
}

我想为 hello() 方法获取 Function 参考。我需要传递方法的名称,在本例中为 "hello" 并获取 Function.

我也可以通过这种方式获得 FunctionTest::hello,但我想做类似的事情,Test::"hello"


@immibis 提到要试试这个:

private Function<Test, Integer> getFunction(String s){
    return (Test o) -> s;
}                      ^

但不幸的是,这样调用它是行不通的,getFunction("hello")。 IntelliJ IDEA 给我这个错误信息:

Bad return type in lambda expression: String cannot be converted to Integer

不是 this 的副本,我不想要 Method 响应,而是 Function 响应。

直觉上,我们已经在我们通常编写的函数(方法)中加入了很多活力:我们使用各种条件分支和循环。如果您可以限制可执行的操作,则可以使用这些简单的结构来构建您的函数。

但是,从您的问题中并不清楚您期望的活力是什么:

  1. 实际java编码
  2. 评估像 1+2*(4-8)
  3. 这样的简单表达式
  4. 或您要解析和评估的其他一些类似构造的脚本

对于实际的 Java 编码,我建议使用 API/SPI 对实现某种抽象。 SPI 是一个服务提供者接口,或允许其他人提供现成和编译的 classes 作为扩展的抽象。我相信 OSGI 提供了执行此操作的标准方法。

要计算表达式,有许多可用的第 3 方库。我开发了一个,但不会提及,因为还有许多其他可用的。该板无意在命令上提出一个工具。您还可以考虑 Nashorn,它是一个 Java脚本引擎。

为了真正允许编写脚本,我建议坚持使用 javascript 并使用 Nashorn. Java allows for plugins and actually enables you to add-in additional scripting engines as part of JSR-223.

[更新]

根据您的说明和示例,是的,我们需要使用某种类型的反射。

在您的情况下,您想懒惰地决定要应用该方法的 class 或实例。这限制了我提供如下解决方案,但是我通过优化一种情况的实现更进一步:其中 class 个实例将应用功能对象或可以预先确定。

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()));
  }
}

请注意,我采用的解决方案适用于静态方法和实例方法。

@JoD.的回答是正确的。这里我采用另一种方法来解决问题,不使用反射:

public class Test {

    private final int number;

    public Test(int number) {
        this.number = number;
    }

    public int increment() {
        return this.number + 1;
    }

    public int decrement() {
        return this.number - 1;
    }

    public static void main(String[] args) {

        // Define references to methods    
        Function<Test, Integer> incr = Test::increment;
        Function<Test, Integer> decr = Test::decrement;

        // Store method references in a map    
        Map<String, Function<Test, Integer>> map = new HashMap<>();
        map.put("incr", incr);
        map.put("decr", decr);

        // Define invocation: based on a string, select method reference to use
        Function<String, Function<Test, Integer>> invocation = k -> map.get(k);

        // Now the test
        Test test1 = new Test(10);

        int incrOnTest1 = invocation.apply("incr").apply(test1);
        int decrOnTest1 = invocation.apply("decr").apply(test1);

        System.out.println(incrOnTest1); // 11
        System.out.println(decrOnTest1); // 9

        Test test2 = new Test(50);

        int incrOnTest2 = invocation.apply("incr").apply(test2);
        int decrOnTest2 = invocation.apply("decr").apply(test2);

        System.out.println(incrOnTest2); // 51
        System.out.println(decrOnTest2); // 49
    }
}

我们的想法是将对方法的引用声明为函数,并将它们存储在映射中,以某个字符串作为键。然后,定义了一个特殊的调用函数,它接收一个字符串并查询映射到 return 对应的方法引用。最后,returned 函数与所需的对象实例一起应用。