2009-05-19 32 views
107

Ho una classe che utilizza XML e reflection per restituire Object in un'altra classe.Un modo per richiamare un metodo privato?

Normalmente questi oggetti sono campi secondari di un oggetto esterno, ma occasionalmente è qualcosa che voglio generare al volo. Ho provato qualcosa di simile ma senza successo. Credo che sia perché Java non ti permetterà di accedere ai metodi di riflessione 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); 

Se il metodo fornito è private, non si effettua con un NoSuchMethodException. Potrei risolverlo creando il metodo public o facendo in modo che un'altra classe la ricava.

Per farla breve, mi chiedevo se c'era un modo per accedere a un metodo private tramite riflessione.

risposta

233

È possibile richiamare il metodo privato con la riflessione. Modifica dell'ultimo bit del codice pubblicato:

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

Ci sono un paio di avvertimenti. Innanzitutto, getDeclaredMethod troverà il metodo dichiarato nell'attuale Class, non ereditato dai supertipi. Quindi, attraversare la gerarchia di classe concreta se necessario. In secondo luogo, un SecurityManager può impedire l'utilizzo del metodo setAccessible. Pertanto, potrebbe essere necessario eseguire come PrivilegedAction (utilizzando AccessController o Subject).

+1

quando ho fatto questo in passato, ho anche chiamato method.setAccessible (false) dopo aver chiamato il metodo, ma non ho idea se questo è necessario o meno. – shsteimer

+12

No, quando si imposta l'accessibilità, si applica solo a quell'istanza. Finché non lasci che quel particolare oggetto Method sfugga al tuo controllo, è sicuro. – erickson

+5

Mi capita assolutamente di amarti amico. Risposta stupefacente + codice errato == Non è un brutto giorno. – droope

32

Utilizzare getDeclaredMethod() per ottenere un oggetto Method privato e quindi utilizzare method.setAccessible() per consentire effettivamente di chiamarlo.

+7

La risposta accettata è in realtà completa. –

+0

Nel mio esempio (http://stackoverflow.com/a/15612040/257233) ottengo un 'java.lang.StackOverflowError' se non chiamo' setAccessible (true) '. –

21

Se il metodo accetta tipo di dati non primitivi quindi il seguente metodo può essere utilizzato per invocare un metodo privato di qualsiasi classe:

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; 
    } 

La parametri accettati sono obj, methodName, il conteggio dei parametri accettati e i parametri. Per esempio

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

Metodo concatString può essere invocata come

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

Perché è necessario _paramCount_? Non puoi semplicemente usare * params.length *? –

Problemi correlati