2013-04-27 11 views
6

JavaDocの状態MethodHandles.lookup()は、このメソッドの呼び出し元と同じメソッド/関数/コンストラクタにアクセスする機能を返します。具体的には、呼び出し側がこのMethodHandles.Lookup機能など、いくつかのプライベートデータにアクセスできるかどうか。以下のコードは、これが誤りであることを示しています。どこが間違っているの?MethodHandle Lookupファシリティ

public class MethodHandlerAccessTest { 

     private static class NestedClass { 
      private static void foo(){} 
     } 

     @Test 
     public void testPrivateAccess() throws Throwable { 
      NestedClass.foo(); //compiles and executes perfectly 
      MethodType type = MethodType.methodType(void.class); 
      MethodHandles.Lookup lookup = MethodHandles.lookup(); 
      MethodHandle mh = lookup.findStatic(NestedClass.class, "foo", type); 
     } 

} 

編集:

これは私が得るものです:

にjava.lang.IllegalAccessException: MethodHandlerAccessTestから、)( MethodHandlerAccessTest $ NestedClass.fooのボイド:メンバーはプライベートです にあるjava.lang.invoke.MemberName.makeAccessException(MemberName.java:507) ( )java.lang.invoke.MethodHandles $ L ookup.checkAccess(MethodHandles.java:1182) java.lang.invoke.MethodHandles $ Lookup.checkMethod(MethodHandles.java:1162) でjava.lang.invoke.MethodHandles $ Lookup.accessStatic(MethodHandles.javaで : 591) MethodHandlerAccessTest.testPrivateAccess(MethodHandlerAccessTest.java:19で java.lang.invoke.MethodHandles $ Lookup.findStatic(MethodHandles.java:587) )sun.reflect.NativeMethodAccessorImpl.invoke0(ネイティブメソッドで )での(NativeMethodAccessorImpl.java:57)at java.lang.reflect.Method.invoke(Method.java:601)at org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners。 org.junit.internal.runners.statements.InvokeMethod.evaluateでmodel.ReflectiveCallable.run(ReflectiveCallable.java:12) でorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) ( InvokeMethod.java:17) org.junit.runnersでorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70でorg.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)) で.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:238)at org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:63)at org.junit.runners.ParentRunner.runChildren ParentRunner.java:236)at org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:53)at org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:229)at org.junit。 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) org.eclipse.jdt.internal.junit.runnerで でrunners.ParentRunner.run(ParentRunner.java:309) .TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(Remo org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runで org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) でteTestRunner.java:467) ( RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner。Javaの:197)

答えて

7

問題は、あなたの試験方法がない本当にコールNestedClass.foo()を行うということです。このライン:

NestedClass.foo(); 

が...実際にこのように、fooで生成され合成法への呼び出しに変換されます。

access$000はこのようになります
NestedClass.access$000(); 

// Note package access 
static void access$000() { 
    foo(); 
} 

javap -cを使用して、実際のバイトコードを確認することでこれを検証できます。

JVMレベルでは、外部クラスはfoo()にアクセスできません。 Javaコンパイラaccess$000を作成し、ソースコードがfoo()のときは常に外部クラスから呼び出して、へのアクセスを合成します。

実行時に、リフレクションライブラリと同じことをしないため、エラーが発生します。

+0

ありがとうございます。私は* synthetic fields/methods *について他のところで聞いたことがありますが、実際にはそれに遭遇したことはありません。なぜMethodHandleはこの動作をシミュレートしませんでしたか? lookup()メソッドのJavaDocから '呼び出し元の参照ハンドルオブジェクトにアクセスできます。呼び出し元がアクセスできるメソッドハンドルにアクセスすることができます。これには、プライベートフィールドとメソッドへのダイレクトメソッドハンドルも含まれます。このルックアップオブジェクトは、信頼できるエージェントに委譲される可能性のある機能です。 ' 私はそれを行うと予想しています。 – alexsmail

+1

@alexsmail:コンパイラは合成メソッドを実装できますが、これを選択します。私は、JREが同じことをやろうとしているとは思っていません。 *言語*があなたに許すものと、*バイトコード*があなたに許すものとを区別することは重要です。 VMに関する限り、あなたは 'foo()'を呼び出すのではなく、アクセスする権限がありません。この言語では、特別な方法を追加して呼び出すことで、特別な権利を与えることができますが、これは単なる言語の問題です。呼び出し元(外部クラス)は実際にはVMの観点から 'foo()'にアクセスできません。 –