Java 有什么方法可以调用私有方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/880365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Any way to Invoke a private method?
提问by Sheldon Ross
I have a class that uses XML and reflection to return Object
s to another class.
我有一个使用 XML 和反射将Object
s返回到另一个类的类。
Normally these objects are sub fields of an external object, but occasionally it's something I want to generate on the fly. I've tried something like this but to no avail. I believe that's because Java won't allow you to access private
methods for reflection.
通常这些对象是外部对象的子字段,但有时我想动态生成它。我试过这样的事情,但无济于事。我相信这是因为 Java 不允许您访问private
反射方法。
Element node = outerNode.item(0);
String methodName = node.getAttribute("method");
String objectName = node.getAttribute("object");
if ("SomeObject".equals(objectName))
object = someObject;
else
object = this;
method = object.getClass().getMethod(methodName, (Class[]) null);
If the method provided is private
, it fails with a NoSuchMethodException
. I could solve it by making the method public
, or making another class to derive it from.
如果提供的方法是private
,则失败并显示NoSuchMethodException
。我可以通过创建方法来解决它public
,或者创建另一个类来派生它。
Long story short, I was just wondering if there was a way to access a private
method via reflection.
长话短说,我只是想知道是否有办法private
通过反射访问方法。
采纳答案by erickson
You can invoke private method with reflection. Modifying the last bit of the posted code:
您可以使用反射调用私有方法。修改发布代码的最后一位:
Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
Object r = method.invoke(object);
There are a couple of caveats. First, getDeclaredMethod
will only find method declared in the current Class
, not inherited from supertypes. So, traverse up the concrete class hierarchy if necessary. Second, a SecurityManager
can prevent use of the setAccessible
method. So, it may need to run as a PrivilegedAction
(using AccessController
or Subject
).
有几个注意事项。首先,getDeclaredMethod
只会在当前声明的 find 方法Class
,而不是从超类型继承。因此,如有必要,请向上遍历具体的类层次结构。其次,一种SecurityManager
可以防止使用的setAccessible
方法。因此,它可能需要作为PrivilegedAction
(使用AccessController
或Subject
)运行。
回答by Mihai Toader
Use getDeclaredMethod()
to get a private Method object and then use method.setAccessible()
to allow to actually call it.
使用getDeclaredMethod()
获得的私有方法的对象,然后使用method.setAccessible()
允许实际调用它。
回答by gKaur
If the method accepts non-primitive data type then the following method can be used to invoke a private method of any class:
如果该方法接受非原始数据类型,则可以使用以下方法调用任何类的私有方法:
public static Object genericInvokeMethod(Object obj, String methodName,
Object... params) {
int paramCount = params.length;
Method method;
Object requiredObj = null;
Class<?>[] classArray = new Class<?>[paramCount];
for (int i = 0; i < paramCount; i++) {
classArray[i] = params[i].getClass();
}
try {
method = obj.getClass().getDeclaredMethod(methodName, classArray);
method.setAccessible(true);
requiredObj = method.invoke(obj, params);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return requiredObj;
}
The Parameter accepted are obj, methodName and the parameters. For example
接受的参数是 obj、methodName 和参数。例如
public class Test {
private String concatString(String a, String b) {
return (a+b);
}
}
Method concatString can be invoked as
方法 concatString 可以调用为
Test t = new Test();
String str = (String) genericInvokeMethod(t, "concatString", "Hello", "Mr.x");
回答by Pavel Chertalev
Let me provide complete code for execution protected methods via reflection. It supports any types of params including generics, autoboxed params and null values
让我通过反射提供执行保护方法的完整代码。它支持任何类型的参数,包括泛型、自动装箱参数和空值
@SuppressWarnings("unchecked")
public static <T> T executeSuperMethod(Object instance, String methodName, Object... params) throws Exception {
return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params);
}
public static <T> T executeMethod(Object instance, String methodName, Object... params) throws Exception {
return executeMethod(instance.getClass(), instance, methodName, params);
}
@SuppressWarnings("unchecked")
public static <T> T executeMethod(Class clazz, Object instance, String methodName, Object... params) throws Exception {
Method[] allMethods = clazz.getDeclaredMethods();
if (allMethods != null && allMethods.length > 0) {
Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new);
for (Method method : allMethods) {
String currentMethodName = method.getName();
if (!currentMethodName.equals(methodName)) {
continue;
}
Type[] pTypes = method.getParameterTypes();
if (pTypes.length == paramClasses.length) {
boolean goodMethod = true;
int i = 0;
for (Type pType : pTypes) {
if (!ClassUtils.isAssignable(paramClasses[i++], (Class<?>) pType)) {
goodMethod = false;
break;
}
}
if (goodMethod) {
method.setAccessible(true);
return (T) method.invoke(instance, params);
}
}
}
throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " +
Arrays.toString(paramClasses));
}
throw new MethodNotFoundException("There are no methods found with name " + methodName);
}
Method uses apache ClassUtils for checking compatibility of autoboxed params
方法使用 apache ClassUtils 检查自动装箱参数的兼容性
回答by Pavel Chertalev
One more variant is using very powerfull JOOR library https://github.com/jOOQ/jOOR
另一种变体是使用非常强大的 JOOR 库https://github.com/jOOQ/jOOR
MyObject myObject = new MyObject()
on(myObject).get("privateField");
It allows to modify any fields like final static constants and call yne protected methods without specifying concrete class in the inheritance hierarhy
它允许修改任何字段,如最终静态常量和调用 yne 受保护的方法,而无需在继承层次结构中指定具体类
<!-- https://mvnrepository.com/artifact/org.jooq/joor-java-8 -->
<dependency>
<groupId>org.jooq</groupId>
<artifactId>joor-java-8</artifactId>
<version>0.9.7</version>
</dependency>
回答by KaderLAB
you can do this using ReflectionTestUtils of Spring (org.springframework.test.util.ReflectionTestUtils)
你可以使用 Spring 的 ReflectionTestUtils ( org.springframework.test.util.ReflectionTestUtils)来做到这一点
ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);
Example : if you have a class with a private method square(int x)
示例:如果您有一个带有私有方法的类 square(int x)
Calculator calculator = new Calculator();
ReflectionTestUtils.invokeMethod(calculator,"square",10);
回答by Scott
You can use Manifold's@Jailbreakfor direct, type-safe Java reflection:
您可以使用Manifold 的@Jailbreak进行直接的、类型安全的 Java 反射:
@Jailbreak Foo foo = new Foo();
foo.callMe();
public class Foo {
private void callMe();
}
@Jailbreak
unlocks the foo
local variable in the compiler for direct access to all the members in Foo
's hierarchy.
@Jailbreak
foo
在编译器中解锁局部变量以直接访问Foo
的层次结构中的所有成员。
Similarly you can use the jailbreak()extension method for one-off use:
同样,您可以使用jailbreak()扩展方法进行一次性使用:
foo.jailbreak().callMe();
Through the jailbreak()
method you can access any member in Foo
's hierarchy.
通过该jailbreak()
方法,您可以访问Foo
的层次结构中的任何成员。
In both cases the compiler resolves the method call for you type-safely, as if a public method, while Manifold generates efficient reflection code for you under the hood.
在这两种情况下,编译器都会以类型安全的方式为您解析方法调用,就像公共方法一样,而 Manifold 会在幕后为您生成高效的反射代码。
Alternatively, if the type is not known statically, you can use Structural Typingto define an interface a type can satisfy without having to declare its implementation. This strategy maintains type-safety and avoids performance and identity issues associated with reflection and proxy code.
或者,如果类型不是静态已知的,您可以使用结构类型定义一个类型可以满足的接口,而无需声明其实现。此策略维护类型安全并避免与反射和代理代码相关的性能和身份问题。
Discover more about Manifold.
了解更多关于歧管的信息。