2013-04-27 12 views
6

जहां तक ​​जावाडोक MethodHandles.lookup() रिटर्न सुविधा है जिसमें इस फ़ंक्शन के कॉलर के समान विधि/फ़ंक्शंस/कन्स्ट्रक्टर तक पहुंचने की क्षमता है। विशेष रूप से, यदि कॉलर कुछ निजी डेटा तक पहुंच सकता है, तो इस विधिHandles.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 $ NestedClass.foo() शून्य MethodHandlerAccessTest से: सदस्य निजी है 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) java.lang.invoke.MethodHandles $ Lookup.findStatic (MethodHandles.java:587) MethodHandlerAccessTest.testPrivateAccess (MethodHandlerAccessTest.java:19 पर) sun.reflect.NativeMethodAccessorImpl.invoke0 (मूल निवासी विधि पर ) पर पर sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:57) sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) पर java.lang.reflect.Method.invoke (method.java:601) org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall (FrameworkMethod.java:47) org.junit.internal.runners पर। model.ReflectiveCallable.run (ReflectiveCallable.java:12) org.junit.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java:44) पर org.junit.internal.runners.statements.InvokeMethod.evaluate पर (InvokeMethod.java:17) org.junit.runners पर org.junit.runners.ParentRunner.runLeaf (ParentRunner.java:271) org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:70 पर) पर .BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:50) org.junit.runners.ParentRunner $ 3.run (ParentRunner.java3838) org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:63) org.junit.runners.ParentRunner.runChildren ( org.junit.runners.ParentRunner.access $ 000 (ParentRunner.java:53) org.junit.runners.ParentRunner $ 2. मूल्यांकन (ParentRunner.java229) org.junit पर। runners.ParentRunner.run org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run (JUnit4TestReference.java:50) पर (ParentRunner.java:309) org.eclipse.jdt.internal.junit.runner पर .TestExecution.run (TestExecution.java:38) org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (Remo teTestRunner.java:467) org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:683) पर org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run पर (RemoteTestRunner.java:390) org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main (RemoteTestRunner।जावा: 197)

उत्तर

7

समस्या यह है कि अपने परीक्षण विधि नहीं वास्तव में कॉल NestedClass.foo() करता है। यह पंक्ति:

NestedClass.foo(); 

... वास्तव में एक फोन में एक सिंथेटिक विधि जो foo में उत्पन्न होता है करने के लिए, तब्दील हो जाता है इस तरह:

NestedClass.access$000(); 

कहाँ access$000 इस तरह दिखता है:

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

वास्तविक बाइटकोड देखने के लिए आप javap -c का उपयोग कर इसे सत्यापित कर सकते हैं।

जेवीएम स्तर पर, आपके बाहरी वर्ग में foo() तक पहुंच नहीं है। जावा कंपाइलर सिर्फ को access$000 बनाकर इसे एक्सेस करने और इसे अपने बाहरी वर्ग से कॉल करने पर संश्लेषित करता है जब भी स्रोत कोड foo() पर कॉल करता है।

निष्पादन समय पर, प्रतिबिंब पुस्तकालय एक ही चीज़ नहीं है, इसलिए आपकी त्रुटि।

+0

आपकी व्याख्या के लिए धन्यवाद। मैंने सिंथेटिक फ़ील्ड/विधियों * के बारे में कहीं और सुना, लेकिन मैंने कभी इसके साथ कभी सामना नहीं किया। क्यों MethodHandle इस व्यवहार का अनुकरण नहीं किया? लुकअप के जावाडॉक() विधि 'कॉलर पर एक लुकअप ऑब्जेक्ट देता है, जिसमें कॉलर के पास किसी भी विधि हैंडल तक पहुंचने की क्षमता है, जिसमें निजी फ़ील्ड और विधियों के लिए सीधे विधि हैंडल शामिल हैं। यह लुकअप ऑब्जेक्ट एक क्षमता है जिसे विश्वसनीय एजेंटों को सौंप दिया जा सकता है। मुझे ऐसा करने की उम्मीद है। – alexsmail

+1

@alexsmail: संकलक सिंथेटिक विधि को कार्यान्वित कर सकता है हालांकि यह चुनता है। मैं चाहता हूं कि जेआरई एक ही काम करने की कोशिश न करे। * भाषा * आपको क्या करने की अनुमति देता है, और * बाइटकोड * आपको क्या करने की अनुमति देता है, इसके बीच अंतर करना महत्वपूर्ण है। जहां तक ​​वीएम का संबंध है, आप 'foo() 'को कॉल नहीं कर रहे हैं, और आपके पास ऐसा करने की पहुंच नहीं है। भाषा आपको अतिरिक्त विधि जोड़कर ऐसा करने के लिए "विशेष" अधिकार देने में सक्षम है - लेकिन यह सिर्फ एक भाषा चिंता है। कॉलर (बाहरी वर्ग) वास्तव में * वीएम के परिप्रेक्ष्य से 'foo()' तक पहुंच नहीं है। –

संबंधित मुद्दे