从另一个类的getter/setter的MethodHandle给出了NoSuchFieldError [英] MethodHandle to a getter/setter from another class gives a NoSuchFieldError

查看:285
本文介绍了从另一个类的getter/setter的MethodHandle给出了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));

findGetterfindSetter方法不会像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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆