就JavaDoc而言,MethodHandles.lookup()
返回能够访问与该函数调用者相同的方法/函数/构造函数的设施。具体来说,如果调用者可以访问一些私有数据,比如这个MethodHandles。查找设备。下面的代码证明这是错误的。我哪里说错了?
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);
}
}
编辑:这是我得到的:
. lang。非法访问异常:成员是私有的:MethodHandlerAccessTest NestedClass.foo美元()无效,MethodHandlerAccessTest在java.lang.invoke.MemberName.makeAccessException (MemberName.java: 507)在java.lang.invoke.MethodHandles Lookup.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(本机方法)atsun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java: 57)在sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java: 43)java.lang.reflect.Method.invoke(Method.java:601org.junit.runners.model.FrameworkMethod runreflectivecall 1.美元(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.ParentRunner.runLeaf(ParentRunner.java:271) atorg.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java: 70)在org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java: 50)在org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) atorg.junit.runners.ParentRunner时间表(ParentRunner.java: 63) 1.美元org.junit.runners.ParentRunner.runChildren (ParentRunner.java: 236)org.junit.runners.ParentRunner.access 000美元(ParentRunner.java: 53)org.junit.runners.ParentRunner评估(ParentRunner.java: 229) 2.美元org.junit.runners.ParentRunner.run (ParentRunner.java: 309)org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run (JUnit4TestReference.java: 50)在org.eclipse.jdt.internal.junit.runner.TestExecution.run (TestExecution.java: 38)在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.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.java: 197)
问题是您的测试方法没有真正调用NestedClass.foo()
。这条线:
NestedClass.foo();
…实际上转换为对foo
中生成的合成方法的调用,如下所示:
NestedClass.access$000();
access$000
看起来像这样:
// Note package access
static void access$000() {
foo();
}
您可以通过使用javap -c
查看实际的字节码来验证这一点。
在JVM级别,外部类没有访问foo()
的权限。Java编译器通过创建access$000
并在源代码调用foo()
时从外部类调用它来合成对它的访问。
在执行时,反射库不做同样的事情,因此你的错误。