使用java.lang.invoke.MethodHandle调用私有方法

如何使用方法句柄调用私有方法?

据我所知,只有两种可公开访问的Lookup实例:

  • MethodHandles.lookup()
  • MethodHandles.publicLookup()

并且都不允许不受限制的私人访问。

有非公开的Lookup.IMPL_LOOKUP我的需求。 是否有一些公共方法来获取它(假设SecurityManager允许它)?

事实certificate,使用Lookup#unreflect(方法)并暂时使方法可访问(除非在程序初始化期间完成,否则可能会引入小的安全问题)。

以下是Thorben回答的修改主要方法:

 public static void main(String[] args) { Lookup lookup = MethodHandles.lookup(); NestedTestClass ntc = new Program().new NestedTestClass(); try { // Grab method using normal reflection and make it accessible Method pm = NestedTestClass.class.getDeclaredMethod("gimmeTheAnswer"); pm.setAccessible(true); // Now convert reflected method into method handle MethodHandle pmh = lookup.unreflect(pm); System.out.println("reflection:" + pm.invoke(ntc)); // We can now revoke access to original method pm.setAccessible(false); // And yet the method handle still works! System.out.println("handle:" + pmh.invoke(ntc)); // While reflection is now denied again (throws exception) System.out.println("reflection:" + pm.invoke(ntc)); } catch (Throwable e) { e.printStackTrace(); } } 

我不知道,如果这是你真正想要的。 也许你可以提供一些关于你想用它实现什么的更多信息。 但是如果你想访问Lookup.IMPL_LOOKUP ,你可以像这个代码示例一样:

 public class Main { public static void main(String[] args) { Lookup myLookup = MethodHandles.lookup(); // the Lookup which should be trusted NestedTestClass ntc = new Main().new NestedTestClass(); // test class instance try { Field impl_lookup = Lookup.class.getDeclaredField("IMPL_LOOKUP"); // get the required field via reflections impl_lookup.setAccessible(true); // set it accessible Lookup lutrusted = (Lookup) impl_lookup.get(myLookup); // get the value of IMPL_LOOKUP from the Lookup instance and save it in a new Lookup object // test the trusted Lookup MethodHandle pmh = lutrusted.findVirtual(NestedTestClass.class, "gimmeTheAnswer", MethodType.methodType(int.class)); System.out.println(pmh.invoke(ntc)); } catch (Throwable e) { e.printStackTrace(); } } // nested class with private method for testing class NestedTestClass{ @SuppressWarnings("unused") private int gimmeTheAnswer(){ return 42; } } } 

它适用于JDK 7,但可能会破坏JDK 8.并且要谨慎! 我的防病毒程序在执行时发出警报。 我认为没有公开或干净的方式来做到这一点。

我遇到了类似的问题,最终找到了解决方案: 从JDK(7)访问非公共(java-native)类 。

这是一个类似的解决方案,其中包含私有函数中的参数(我恰好让代码位于前一个项目中):

类名:InspectionTree.java

function signature:private String getSamePackagePathAndName(String className,String classPath)

 String firstName = "John"; String lastName = "Smith"; //call the class's constructor to set up the instance, before calling the private function InspectionTree inspectionTree = new InspectionTree(firstName, lastName); String privateMethodName ="getSamePackagePathAndName"; Class[] privateMethodArgClasses = new Class[] { String.class, String.class }; Method method = inspectionTree.getClass().getDeclaredMethod(privateMethodName, privateArgClasses); method.setAccessible(true); String className = "Person"; String classPath = "C:\\workspace"; Object[] params = new Object[]{className, classPath}; //note the return type of function 'getSamePackagePathAndName' is a String, so we cast //the return type here as a string String answer= (String)method.invoke(inspectionTree, params); method.setAccessible(false);