我该如何使用方法句柄调用私有方法呢?
据我所知,只有两种公共可访问的Lookup
实例:
MethodHandles.lookup()
MethodHandles.publicLookup()
但是它们都不允许无限制的私有访问。
有一个非公共的Lookup.IMPL_LOOKUP
可以满足我的需求。是否有一些公共的方法可以获取它(假设安全管理器允许)?
我该如何使用方法句柄调用私有方法呢?
据我所知,只有两种公共可访问的Lookup
实例:
MethodHandles.lookup()
MethodHandles.publicLookup()
但是它们都不允许无限制的私有访问。
有一个非公共的Lookup.IMPL_LOOKUP
可以满足我的需求。是否有一些公共的方法可以获取它(假设安全管理器允许)?
通过Lookup#unreflect(Method)并临时使方法可访问(可能会在程序初始化期间引入小的安全问题),原来的方法是可以实现的。
这里是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)类。
java.lang.reflect.*
使用公共 API 尝试访问私有成员。我正在询问是否可以使用 java.lang.invoke.*
实现相同的功能。 - Marcin Wisnicki这里有一个类似的解决方案,其中包括私有函数中的参数(我碰巧从以前的项目中找到了代码):
类名: InspectionTree.java
函数签名: 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);
setAccessible
来获取特殊的特权实现Lookup
,才能调用私有成员,而不管它们是否对调用者可访问。 - Marcin Wisnicki