Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java MethodHandle查找工具_Java_Reflection_Java 7 - Fatal编程技术网

Java MethodHandle查找工具

Java MethodHandle查找工具,java,reflection,java-7,Java,Reflection,Java 7,就JavaDoc而言,MethodHandles.lookup()返回能够访问与此函数调用方相同的方法/函数/构造函数的工具。具体地说,如果调用方可以访问一些私有数据,那么这个MethodHandles.Lookup工具可以处理这些数据。下面的代码表明这是错误的。我哪里弄错了 public class MethodHandlerAccessTest { private static class NestedClass { private static

就JavaDoc而言,
MethodHandles.lookup()
返回能够访问与此函数调用方相同的方法/函数/构造函数的工具。具体地说,如果调用方可以访问一些私有数据,那么这个MethodHandles.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.IllegalacessException:成员是私有的: 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(本机方法) 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.runReflectVeCall(FrameworkMethod.java:47) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeeexplosive(FrameworkMethod.java:44) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 位于org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 位于org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)位于 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)位于 org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)位于 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)位于 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();
// Note package access
static void access$000() {
    foo();
}
其中
access$000
如下所示:

NestedClass.access$000();
// Note package access
static void access$000() {
    foo();
}
您可以通过使用
javap-c
查看实际字节码来验证这一点

在JVM级别,您的外部类无权访问
foo()
。Java编译器只是通过创建
access$000
并在源代码调用
foo()
时从外部类调用它来综合对它的访问


在执行时,反射库不会执行相同的操作,因此会出现错误。

感谢您的解释。我在别处听说过合成领域/方法,但我从未真正遇到过。为什么MethodHandle没有模拟这种行为?从JavaDoc of lookup()方法
返回调用者的查找对象,该对象能够访问调用者有权访问的任何方法句柄,包括私有字段和方法的直接方法句柄。这个查找对象是一个可以委托给受信任代理的功能。
我希望这样做。@alexsmail:编译器可以实现它选择的合成方法。我不希望JRE尝试做同样的事情。区分语言允许您做什么和字节码允许您做什么很重要。就VM而言,您没有调用
foo()
,您也无权这样做。通过添加额外的方法并调用它,该语言可以为您提供“特殊”的权限,但这只是语言问题。从VM的角度来看,调用方(外部类)实际上没有访问
foo()
的权限。虽然有点晚,但有一个简单的解决方法。将(NestedClass.class)中的
MethodHandles.lookup()替换为
MethodHandles.lookup()。以这种方式在外部类和内部类之间更改上下文类时,会保留私有访问功能,因此之后,可以访问嵌套类的
private
成员。除此之外,从Java11开始,不再需要这个
access$…
东西,但它还需要使用JDK11目标编译代码。