【问题标题】:How to get Method Reference for all methods in a class (Java)?如何获取类中所有方法的方法参考(Java)?
【发布时间】:2015-03-30 13:25:45
【问题描述】:
Java 8 中特定方法的

方法参考可以通过Class::Method 获得。但是如何获取一个类的所有方法的方法引用呢?

所有需要的方法都有不同的方法名称,但是相同的类型签名。此外,方法的名称事先未知

例子:

class Test {
    public static double op0(double a) { ... }
    public static double op1(double a) { ... }
    public static double op2(double a) { ... }
    public static double op3(double a) { ... }
    public static double op4(double a) { ... }
}

已知方法op0的方法引用可以得到如下:

DoubleFunction<Double> f = Test::op0;

但是,如何获取类中所有方法的方法引用呢?

【问题讨论】:

  • 您的意思是如何在 IDE 的内容辅助中获取这些内容?
  • 否,获取方法引用,以便以后可以调用它们。这可以使用Reflection,但我正在寻找更简单的替代方案。
  • 另外声明所需的方法具有不同的函数名称,但相同的函数签名是错误的。签名包括方法名称和参数列表。返回类型不是方法签名的一部分。
  • 对不起,我的错误。它应该被称为Type Signature

标签: java java-8 method-reference


【解决方案1】:

没有反射没有解决方案,因为现有方法的动态发现反射操作。但是,一旦发现方法并创建了方法引用实例(或它的动态等价物),代码的实际调用就会在没有反射的情况下运行:

class Test {
    public static double op0(double a) { ... }
    public static double op1(double a) { ... }
    public static double op2(double a) { ... }
    public static double op3(double a) { ... }
    public static double op4(double a) { ... }

    static final Map<String, DoubleUnaryOperator> OPS;
    static {
        HashMap<String, DoubleUnaryOperator> map=new HashMap<>();
        MethodType type=MethodType.methodType(double.class, double.class);
        MethodType inT=MethodType.methodType(DoubleUnaryOperator.class);
        MethodHandles.Lookup l=MethodHandles.lookup();
        for(Method m:Test.class.getDeclaredMethods()) try {
          if(!Modifier.isStatic(m.getModifiers())) continue;
          MethodHandle mh=l.unreflect(m);
          if(!mh.type().equals(type)) continue;
          map.put(m.getName(), (DoubleUnaryOperator)LambdaMetafactory.metafactory(
            l, "applyAsDouble", inT, type, mh, type).getTarget().invokeExact());
        } catch(Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
        OPS=Collections.unmodifiableMap(map);
    }
}

一旦类被初始化,您可以使用 OPS.get(name).applyAsDouble(doubleValue) 调用不带反射的特定操作,或者使用例如调用所有操作,例如

OPS.forEach((name,op)-> System.out.println(name+'('+42+") => "+op.applyAsDouble(42)));

【讨论】:

  • 谢谢@Holger。我已经找到了您的答案herehere,这解决了我的问题。这有助于我对实例方法做同样的事情。确实很快。
  • 你为什么用DoubleUnaryOperator而不是DoubleFunction?又如何"applyAsDouble"方法名不指定类或接口名就够了?
  • DoubleFunction 是一个使用double 并返回Object 的函数; DoubleUnaryOperator 使用 double 并返回 double,因此与示例中的方法签名完美匹配。所需的interface 派生自invokedynamic 指令的返回类型;在我们的反射用法中,它出现了两次。 invokedType 参数(inT 变量)指定返回类型,我们的 invokeExact() 调用是 签名多态 并使用我们的类型转换 (DoubleUnaryOperator) 来确定返回类型,当然,必须与inT匹配。
  • 嗨,如果方法“op”不是静态的,那么请引用特定类型的任意对象的实例方法。那么如何获得这种地图呢?
  • @Kristoff 你必须做出决定。您是否想在创建时绑定(捕获)特定实例,以便在评估 DoubleUnaryOperator 时始终使用它,或者您是否想在每次评估函数时传递一个实例(可能每次都不同) . this answer 在一个示例中讨论了这两个选项。但是,对于第二种情况,您需要一个自定义接口来使用一个对象和一个 double 并生成一个 double(除非您可以使用拳击)。
猜你喜欢
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
相关资源
最近更新 更多