使用 java.lang.invoke.MethodHandle 调用私有方法
2022-09-04 02:51:31
如何使用方法句柄调用私有方法?
据我所知,只有两种可公开访问的实例:Lookup
MethodHandles.lookup()MethodHandles.publicLookup()
并且两者都不允许不受限制的私有访问。
有非公众做我想做的事。有没有一些公共方法来获取它(假设SecurityManager允许它)?Lookup.IMPL_LOOKUP
如何使用方法句柄调用私有方法?
据我所知,只有两种可公开访问的实例:Lookup
MethodHandles.lookup()MethodHandles.publicLookup()并且两者都不允许不受限制的私有访问。
有非公众做我想做的事。有没有一些公共方法来获取它(假设SecurityManager允许它)?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)类。