4

getter と setterを持つ単純な javabeanMyPersonがあるとします。name

public class MyPerson {

    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

今、私は単にそのnameフィールドを取得して設定するこのメイン コードを実行しています。

    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());
    }

そのmain()メソッドを classに追加するとMyPerson、期待どおりの結果が得られます。

Name from getterMethodHandle: Batman
Name after setterMethodHandle: Robin

別のパッケージの別のクラスに同じmain()メソッドを追加すると、次の奇妙なエラーが発生します。

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)

なんで?の getter/setter は public であるため、MethodHandles を介しても使用しないMyPerson理由はありません。MyMain

ソース/ターゲット レベルの Java 8 で JDK 8 を使用する。

4

2 に答える 2

5

あなたは物事を混ぜています。必要なものは次のとおりです。

MethodHandle getterMethodHandle = lookup.findVirtual(MyPerson.class,
        "getName", MethodType.methodType(String.class));
MethodHandle setterMethodHandle = lookup.findVirtual(MyPerson.class,
        "setName", MethodType.methodType(void.class, String.class));

findGetterandメソッドはfindSetter、Java Beans のように getXXX または setXXX メソッドを見つけようとしません。メソッド ハンドルは非常に低レベルのものであることを忘れないでください。これらのメソッドは、実際には、既存のメソッドを指すのではなく、指定された名前でフィールドを設定するだけのメソッド ハンドルを構築します。を使用findGetterする場合、クラスに実際の getter メソッドを含める必要はありませんが、フィールドに直接アクセスできる必要があります。のように getter メソッドを使用する場合getNameでも、findVirtual呼び出しが必要です。

一般に、メソッド ハンドルは、メソッドへの単なる参照よりもはるかに強力です。たとえば、メソッド ハンドルを 1 つまたは複数のパラメーターにバインドできるため、呼び出し時に指定する必要はありません。

于 2015-12-03T15:27:44.760 に答える
1

Lookupのドキュメントを確認すると、次のことがわかります。

ファクトリ メソッドによって作成された各メソッド ハンドルは、特定のバイトコード動作と機能的に同等です。

たとえば、ゲッター ルックアップ:

lookup.findGetter(C.class,"f",FT.class)

に翻訳されます:

 (T) this.f;

NoSuchFieldError: nameしたがって、外部からプライベート フィールドを参照していたため、奇妙なエラーが発生しました。ゲッター/セッターの場合は、findVirtual.

于 2015-12-03T15:34:06.337 に答える