2009-05-19 2 views
107

У меня есть класс, который использует 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 через отражение.

ответ

233

Вы можете использовать частный метод с отражением. Изменение последнего бита опубликованного кода:

Method method = object.getClass().getDeclaredMethod(methodName); 
method.setAccessible(true); 
Object r = method.invoke(object); 

Существует несколько предостережений. Сначала getDeclaredMethod найдет только метод, объявленный в текущем Class, не унаследованный от супертипов. Итак, перейдите по иерархии конкретного класса, если это необходимо. Во-вторых, SecurityManager может предотвратить использование метода setAccessible. Таким образом, может потребоваться выполнить его как PrivilegedAction (используя AccessController или Subject).

+1

Когда я это делал в прошлом, я также вызвал метод.setAccessible (false) после вызова метода, но я понятия не имею, нужно ли это или нет. – shsteimer

+12

Нет, когда вы устанавливаете доступность, оно применяется только к этому экземпляру. Пока вы не позволяете этому конкретному методу выйти из своего контроля, это безопасно. – erickson

+5

Я абсолютно любуюсь любовью с тобой. Удивительный ответ + плохой код == Не так плохой день. – droope

32

Используйте getDeclaredMethod(), чтобы получить частный объект метода, а затем используйте method.setAccessible(), чтобы разрешить его на самом деле.

+7

Принятого Ответ на самом деле завершен. –

+0

В моем собственном примере (http://stackoverflow.com/a/15612040/257233) Я получаю 'java.lang.StackOverflowError', если не называть' setAccessible (true) '. –

21

Если метод принимает тип непримитивных данных, то следующий метод может быть использован для вызова частного метода любого класса:

public static Object genericInvokMethod(Object obj, String methodName, 
      int paramCount, Object... params) { 
     Method method; 
     Object requiredObj = null; 
     Object[] parameters = new Object[paramCount]; 
     Class<?>[] classArray = new Class<?>[paramCount]; 
     for (int i = 0; i < paramCount; i++) { 
      parameters[i] = params[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, имяМетод, количество параметров, принимаемый и параметры. Например

public class Test { 
private String concatString(String a, String b) { 
    return (a+b); 
} 
} 

Метод concatString может быть использован в качестве

Test t = new Test(); 
    String str = (String) genericInvokMethod(t, "concatString", 2, "Hello", "Mr.x"); 
+5

Зачем нужен _paramCount_? Вы не можете использовать * params.length *? –

Смежные вопросы