我正在寻找一种从方法中获取Method对象的方便的解决方法.想法:
Method fooMethod = getMethod( new MyObject().foo() ) // returns method "foo" in MyObject
Run Code Online (Sandbox Code Playgroud)
显而易见的方法是将方法的名称用作字符串:
Method fooMethod = MyObject.class.getMethod("foo")
Run Code Online (Sandbox Code Playgroud)
但我想避免这种情况,因为如果我重命名foo()代码将停止工作或我在所有使用它的地方重命名字符串.
用例是我想使用类似于ProperyChangeListeners的东西,但是那些依赖于方法名称作为字符串.我想使用实际的方法(安全)而不依赖于字符串.
我可以使用什么来重命名安全方法?
更新:我想找到一个不依赖IDE功能的纯Java解决方案
我想使用静态方法作为setter helper来捕获异常并打印有关失败操作的调试信息.我不希望只有例外细节.我想显示正在设置的属性,以便详细帮助快速调试问题.我正在使用Java 8.
我应该如何提供或检测所设置的财产?
我希望删除示例中的"名称"字符串并获得相同的结果.
我知道我不能对提供的提供的setter方法使用反射,该方法转换为lambda表达式然后转换为BiConsumer.
我得到了这个,但需要提供属性名称.
/** setter helper method **/
private static <E, V> void set(E o, BiConsumer<E, V> setter,
Supplier<V> valueSupplier, String propertyName) {
try {
setter.accept(o, valueSupplier.get());
} catch (RuntimeException e) {
throw new RuntimeException("Failed to set the value of " + propertyName, e);
}
}
Run Code Online (Sandbox Code Playgroud)
例:
Person p = new Person();
Supplier<String> nameSupplier1 = () -> "MyName";
Supplier<String> nameSupplier2 = () -> { throw new RuntimeException(); };
set(p, Person::setName, nameSupplier1, "name");
System.out.println(p.getName()); // prints MyName …
Run Code Online (Sandbox Code Playgroud) 假设我有一些像Function这样的函数接口和一些不同类的方法,我可以为它们提供方法引用,例如:
class A {
public int getPrimitive() { return 0; }
public Integer getBoxed() { return 0; }
public static int getStaticPrimitive(A a) { return 1; }
}
Function<A, Integer> primitive = A::getPrimitive;
Function<A, Integer> boxed = A::getBoxed;
Function<A, Integer> staticPrimitive = A::getStaticPrimitive;
Run Code Online (Sandbox Code Playgroud)
我如何通过反射获取从A类转换为Function接口实例的所有可能的方法引用?
到目前为止,这个问题与评论中提到的任何问题都不重复,但多亏了Holger在评论中提到的两个问题,我已经设法做了我需要的事情:
class Test {
public static void main(String[] args) throws Throwable {
HashMap<String, Function<A, Integer>> map = new HashMap<>();
Collection<MethodType> supportedTypes = Arrays.asList(
MethodType.methodType(int.class, A.class),
MethodType.methodType(Integer.class, A.class)
);
MethodType inT = MethodType.methodType(Function.class);
MethodHandles.Lookup …
Run Code Online (Sandbox Code Playgroud) 我想捕获对模拟对象的调用
public interface Service {
public String stringify(Object o);
}
service = mockery.mock(Service.class);
mockery.allowing(service::stringify).with(42).will(() -> "42");
Run Code Online (Sandbox Code Playgroud)
所以里面allowing
我有一个Function<Object, String>
是否有任何reflecto-magic可以让我从方法参考创建的函数中找到服务?
public WithClause allowing(Function<T,R> f) {
Object myServiceBackAgain = findTargetOf(function);
....
}
Run Code Online (Sandbox Code Playgroud)
我知道函数将始终来自这些方法引用,所以我很乐意尽可能地向下转换.
这与相关的问题不同是否可以将方法引用转换为MethodHandle?因为,一开始它不是同一个问题,只是在相关领域.即使我可以得到一个MethodHandle,我也无法从中获取目标.
从简单的角度来看,lambda表达式被编译成static
方法,因为它们不捕获this
(即不访问实例成员).
public class App {
public static void foo(){
Consumer<Integer> c1 = n -> {};
Consumer<Integer> c2 = n -> {};
}
public static void main(String [] args) {
Supplier<String> sup1 = () -> "I am sup1";
Supplier<String> sup2 = () -> "I am sup2";
Supplier<String> sup3 = () -> "I am sup3";
Stream.of(App.class.getDeclaredMethods()).forEach(System.out::println);
}
}
Run Code Online (Sandbox Code Playgroud)
运行前面的例子,并检查与生成的字节码javap
工具,我们可以看到,通过变量称为lambda表达式c1
,c2
,sup1
,sup2
,sup3
被编译成与名称的方法:
lambda$foo$0
lambda$foo$1
lambda$main$2
lambda$main$3
lambda$main$4
然而,如果我们打印出getClass() …
我最近使用了很多方法引用和 lambda,并且想知道在运行时是否可以打印以屏幕 lambda 的源(即它的名称),只是出于调试原因。我认为可以使用反射,通过在 getName() 中调用 getClass() 来实现,但我找不到用于查找原始源引用名称的方法。
我有一个功能界面,例如:
@FunctionalInterface
public interface FooInterface {
// function etc etc irrelevant
public void method();
public default String getName() {
// returns the name of the method reference which this is used to define
}
}
Run Code Online (Sandbox Code Playgroud)
然后假设我希望测试运行该界面,并将功能界面的源代码打印到屏幕上。
public static void doStuff(FooInterface f) {
// prints the lambda name that is used to create f
System.out.println(f.getName());
// runs the method itself
f.method();
}
Run Code Online (Sandbox Code Playgroud)
所以如果我这样做:
doStuff(Foo::aMethodReference);
Run Code Online (Sandbox Code Playgroud)
它应该在屏幕上打印类似:“aMethodReference”的内容,这样我就可以知道在运行时正在运行哪些方法,以什么顺序运行等。
考虑到 lambda 不完全是对象,我很怀疑这是可能的,但是嘿,我想可能有一个解决方法。此外,eclipse调试工具只是说它是一个lambda,没有任何其他信息,lambda是否保留任何这些信息?或者在运行时全部丢失?
干杯。(如果有什么区别的话,我正在使用 JDK 11)
我本质上是在问与这个老问题相同的问题,但针对的是 Java 14 而不是 Java 8。为了避免回答者导航到老问题的麻烦,我将在这里重新表述。我想从引用的方法中获取函数的名称。下面的 Java 代码应该能让您明白:
public class Main
{
public static void main(String[] args)
{
printMethodName(Main::main);
}
private static void printMethodName(Consumer<String[]> theFunc)
{
String funcName = // somehow get name from theFunc
System.out.println(funcName)
}
}
Run Code Online (Sandbox Code Playgroud)
C# 中的等效内容是:
public class Main
{
public static void Main()
{
var method = Main.Main;
PrintMethodName(method)
}
private static void PrintMethodName(Action action)
{
Console.WriteLine(action.GetMethodInfo().Name);
}
}
Run Code Online (Sandbox Code Playgroud)
根据老问题的公认答案,如果没有大量的工作,这在 Java 8 中是不可能的,例如这个解决方案。Java 14中有更优雅的解决方案吗?