从另一个类的getter/setter的MethodHandle给出了NoSuchFieldError [英] MethodHandle to a getter/setter from another class gives a NoSuchFieldError
问题描述
假设我有一个简单的javabean MyPerson
,它带有一个name
getter和setter:
Suppose I have simple javabean MyPerson
with a name
getter and setter:
public class MyPerson {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
现在,我正在运行此主要代码,该代码简单地获取并设置了name
字段:
Now I am running this main code that simply gets and sets that name
field:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle getterMethodHandle = lookup.findGetter(MyPerson.class, "name", String.class);
MethodHandle setterMethodHandle = lookup.findSetter(MyPerson.class, "name", String.class);
MyPerson a = new MyPerson();
a.setName("Batman");
System.out.println("Name from getterMethodHandle: " + getterMethodHandle.invoke(a));
setterMethodHandle.invoke(a, "Robin");
System.out.println("Name after setterMethodHandle: " + a.getName());
}
如果在类MyPerson
上添加该main()
方法,我将得到期望的结果:
If I add that main()
method on the class MyPerson
, I get what I expect:
Name from getterMethodHandle: Batman
Name after setterMethodHandle: Robin
如果我在另一个包中的另一个类上添加相同的main()
方法,则会收到此奇怪的错误消息:
If I add that same main()
method on another class in another package, I get this weird error:
Exception in thread "main" java.lang.NoSuchFieldException: no such field: batman.other.MyMain.name/java.lang.String/getField
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:875)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1373)
at java.lang.invoke.MethodHandles$Lookup.findGetter(MethodHandles.java:1022)
at batman.other.MyMain.main(MyMain.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.NoSuchFieldError: name
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
为什么? MyPerson
的getter/setter是公开的,因此没有理由MyMain
即使通过MethodHandles也不应使用它们.
Why? MyPerson
's getter/setters are public, so there's no reason why MyMain
shouldn't be to use them, even through MethodHandles.
在源/目标级别的Java 8中使用JDK 8.
Using JDK 8 with source/target level java 8.
推荐答案
您正在混合各种东西.您需要的是:
You are mixing the things. What you need is:
MethodHandle getterMethodHandle = lookup.findVirtual(MyPerson.class,
"getName", MethodType.methodType(String.class));
MethodHandle setterMethodHandle = lookup.findVirtual(MyPerson.class,
"setName", MethodType.methodType(void.class, String.class));
findGetter
和findSetter
方法不会像Java Beans那样尝试找到一些getXXX或setXXX方法.不要忘记方法句柄是非常底层的东西.这些方法实际上会构建一个方法句柄,该句柄不指向现有方法,而只是使用给定名称设置字段.使用findGetter
,您无需在类中使用实际的getter方法,但必须直接访问该字段.如果要使用getName
之类的getter方法,则仍然需要findVirtual
调用.
The findGetter
and findSetter
methods do not try to find some getXXX or setXXX methods like in Java Beans. Don't forget that method handles are very low-level stuff. These methods actually build a method handle which does not point to an existing method, but just sets the field with given name. Using findGetter
you don't need to have an actual getter method in your class, but you must have a direct access to the field. If you want to use the getter method like getName
, you'll still need a findVirtual
call.
通常,方法句柄比仅引用方法要强大得多.例如,您可以将方法句柄绑定到一个或多个参数,因此您无需在调用时指定它们.
In general method handles are much more powerful than just references to the methods. For example, you can bind method handle to one or several parameters, so you will not need to specify them on the invocation.
这篇关于从另一个类的getter/setter的MethodHandle给出了NoSuchFieldError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!