Любой способ вызвать частный метод?
у меня есть класс, который использует XML и отражение для возврата Object
s в другой класс.
обычно эти объекты являются подполями внешнего объекта, но иногда это то, что я хочу создать на лету. Я пробовал что-то вроде этого, но безрезультатно. Я считаю, что это потому, что 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);
если метод это private
, это не с NoSuchMethodException
. Я мог бы решить это, сделав метод public
, или создание другого класса для его наследования.
короче говоря, мне просто интересно, есть ли способ получить доступ к private
способ через отражение.
6 ответов:
вы можете вызвать частный метод с отражением. Изменение последнего бита опубликованного кода:
Method method = object.getClass().getDeclaredMethod(methodName); method.setAccessible(true); Object r = method.invoke(object);
есть несколько предостережений. Во-первых,
getDeclaredMethod
найдет только метод, объявленный в текущемClass
, не наследуется от супертипов. Таким образом, при необходимости пройдите вверх по конкретной иерархии классов. Во-вторых,SecurityManager
может предотвратить использованиеsetAccessible
метод. Так что, возможно, потребуется запустить какPrivilegedAction
(черезAccessController
илиSubject
).
использовать
getDeclaredMethod()
чтобы получить частный объект метода, а затем использоватьmethod.setAccessible()
разрешить назвать.
Если метод принимает непримитивный тип данных, то для вызова частного метода любого класса можно использовать следующий метод:
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; }
принимаются следующие параметры: obj, methodName и parameters. Например
public class Test { private String concatString(String a, String b) { return (a+b); } }
метод concatString может быть вызван как
Test t = new Test(); String str = (String) genericInvokeMethod(t, "concatString", "Hello", "Mr.x");
позвольте мне предоставить полный код для выполнения защищенных методов через отражение. Он поддерживает любые типы параметров, включая дженерики, автобоксинговые параметры и нулевые значения
@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); }
метод использует Apache ClassUtils для проверки совместимости autoboxed params
вы можете сделать это с помощью ReflectionTestUtils весны (орг.springframework.тест.утиль.ReflectionTestUtils)
ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);
пример : если у вас есть класс с частным методом
square(int x)
Calculator calculator = new Calculator(); ReflectionTestUtils.invokeMethod(calculator,"square",10);
еще один вариант использует очень мощную библиотеку JOOR https://github.com/jOOQ/jOOR
MyObject myObject = new MyObject() on(myObject).get("privateField");
Это позволяет изменять любые поля, такие как конечные статические константы и вызывать защищенные методы 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>