2016-08-22 86 views
2

我试图创建一个变量的方法参考,其持有方法名从对象的一些方法:变量法参考8

SomeClass obj = new SomeClass(); 
String methodName = "someMethod"; 

我正在寻找方法来创建准确obj::someMethod,但为此使用变量methodName。可能吗?

我知道如何从methodNameobj创建功能接口实例:

() -> { 
    try { 
     return obj.getClass().getMethod(methodName).invoke(obj); 
    } catch (NoSuchMethodException | IllegalAccessException e) { 
     return null; 
    } 
}; 

但我想知道这是可以更简便方法来完成。

+2

这是一个非常罕见的情况 - Java8语法糖为此进行了优化的可能性很小。如果这在你的代码库中很常见,你可以将它移动到一个辅助方法中,然后执行'() - > Utils.invoke(obj,methodName)'。 –

+0

@OliverCharlesworth建议做什么是唯一的方法,这可能是一个答案 – Andremoniy

+0

@Andremoniy不仅。还有运行时代码。 – talex

回答

1

这是一个非常罕见的情况 - Java8语法糖为此进行了优化的可能性很小。特别是,通常的编译时类型检查不可能发生(请记住,方法引用只是符合特定类型合约的匿名类的语法糖)。

如果这种模式在您的代码库中很普遍(希望它不是!),您可以将它移动到静态实用程序方法中,然后执行() -> Utils.invoke(obj, methodName)

1

如果您追求简洁而非性能,自Java 1.4以来有ExpressionStatement

Object obj="example"; 
String methodName="substring"; 
Object[] arg={ 2, 5 }; 
try { 
    Object result=new Expression(obj, methodName, arg).getValue(); 
    new Statement(System.out, "println", new Object[]{ result }).execute(); 
} catch (Exception ex) { 
    Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex); 
} 

但是,如果你想在标准功能接口,不允许checked异常的情况下使用它们,异常处理将主导源代码。


可以即使在Java 7中结合一个反射性获取方法将一个功能接口:

Object obj="example"; 
String methodName="substring"; 
Object[] arg={ 2, 5 }; 
Supplier<String> s; 
Consumer<String> c; 
try { 
    MethodHandle mh=MethodHandles.insertArguments(
     MethodHandles.lookup().bind(obj, methodName, 
      MethodType.methodType(String.class, int.class, int.class)), 
     0, arg); 
    s = MethodHandleProxies.asInterfaceInstance(Supplier.class, mh); 
    mh=MethodHandles.lookup().bind(System.out, "println", 
     MethodType.methodType(void.class, String.class)); 
    c = MethodHandleProxies.asInterfaceInstance(Consumer.class, mh); 
} catch(NoSuchMethodException | IllegalAccessException ex) { 
    Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex); 
    return; 
} 
String result=s.get(); 
c.accept(result); 

这不是短,但避免了在每个功能的评价进行反射查找。


可能更有效方法是使用在Java中8,这是在运行时lambda表达式和方法引用的后端导入的LambdaMetafactory

Object obj="example"; 
String methodName="substring"; 
Object[] arg={ 2, 5 }; 
Supplier<String> s; 
Consumer<String> c; 
try { 
    final MethodHandles.Lookup lookup = MethodHandles.lookup(); 
    MethodHandle mh=lookup.findVirtual(String.class, methodName, 
     MethodType.methodType(String.class, int.class, int.class)); 
    s = (Supplier<String>)LambdaMetafactory.metafactory(lookup, "get", 
     mh.type().changeReturnType(Supplier.class), 
     MethodType.methodType(Object.class), mh, MethodType.methodType(String.class)) 
     .getTarget().bindTo(obj).invokeWithArguments(arg); 
    mh=MethodHandles.lookup().findVirtual(PrintStream.class, "println", 
     MethodType.methodType(void.class, String.class)); 
    c = (Consumer<String>)LambdaMetafactory.metafactory(lookup, "accept", 
     MethodType.methodType(Consumer.class, PrintStream.class), 
     MethodType.methodType(void.class, Object.class), mh, 
     MethodType.methodType(void.class, String.class)) 
     .getTarget().bindTo(System.out).invokeExact(); 
} catch(Throwable ex) { 
    Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex); 
    return; 
} 
String result=s.get(); 
c.accept(result); 

这具有较高创作的复杂性,但由于没有技术差异不再职能的后续执行会对编译时方法引用比肩的效率。