2010-04-05 14 views
15

Dato:Java getMethod con i parametri superclasse nel metodo

class A 
{ 
    public void m(List l) { ... } 
} 

Diciamo che voglio richiamare il metodo m con la riflessione, passando un ArrayList come parametro per m:

List myList = new ArrayList(); 
A a = new A(); 
Method method = A.class.getMethod("m", new Class[] { myList.getClass() }); 
method.invoke(a, Object[] { myList }); 

La getMethod on line 3 genererà NoSuchMethodException perché il tipo di runtime di myList è ArrayList, non List.

Esiste un modo generico per aggirare questo problema che non richiede la conoscenza dei tipi di parametri della classe A?

risposta

18

Se si conosce il tipo è List, quindi utilizzare List.class come argomento.

Se non si conosce il tipo in anticipo, immaginate di avere:

public void m(List l) { 
// all lists 
} 

public void m(ArrayList l) { 
    // only array lists 
} 

Quale metodo deve richiamare il riflesso, se non v'è alcun modo automatico?

Se si desidera, è possibile utilizzare Class.getInterfaces() o Class.getSuperclass() ma questo è specifico caso.

Che cosa si può fare qui è:

public void invoke(Object targetObject, Object[] parameters, 
     String methodName) { 
    for (Method method : targetObject.getClass().getMethods()) { 
     if (!method.getName().equals(methodName)) { 
      continue; 
     } 
     Class<?>[] parameterTypes = method.getParameterTypes(); 
     boolean matches = true; 
     for (int i = 0; i < parameterTypes.length; i++) { 
      if (!parameterTypes[i].isAssignableFrom(parameters[i] 
        .getClass())) { 
       matches = false; 
       break; 
      } 
     } 
     if (matches) { 
      // obtain a Class[] based on the passed arguments as Object[] 
      method.invoke(targetObject, parametersClasses); 
     } 
    } 
} 
+1

I miei pensieri esattamente. –

+0

Non conosco il tipo in anticipo. Mi aspetterei 'm2' nel tuo esempio se il mio l.getClass() restituisce ArrayList come tipo di runtime, ma forse mi aspetto troppo? –

+0

esattamente. Ma tu vuoi eseguire il primo metodo a seconda che esista o no il secondo. Non puoi farlo. – Bozho

1

Invece di myList.getClass(), perché non passare semplicemente in List.class? Che è ciò che il tuo metodo è in attesa.

+0

In realtà non ho conoscenza di esattamente quale metodo viene chiamato. Non c'è solo 'm', ci sono molti metodi con diversi tipi di parametri. –

+1

Hai bisogno di sapere a priori cosa stai per chiamare. La riflessione non è come la magia. È necessario specificare il nome del metodo e la firma del metodo a cui si desidera accedere tramite riflessione. A volte devi anche sapere quale versione di un metodo devi chiamare (.ie. Devi accedere alla versione di un metodo "m" definita da una delle tue super classi. –

+0

@luis: sono d'accordo con il tuo punto di dire non ti aiuterà a scegliere un metodo, ma non sono d'accordo sul fatto che devi conoscere a priori quale metodo esatto chiamerai. In un contesto di interprete/linguaggio dinamico, tutto ciò che hai è un nome di metodo, argomenti e se sei fortunato hai qualche suggerimento da parte dell'utente.Il divario tra la materia prima fornita dall'API di reflection e il picking dei metodi applicabili basati sui tipi di argomento deve essere fornito da qualcosa a livello di applicazione dell'interprete. –

1

Sto indovinando che si desidera getDeclaredMethods(). Ecco uno example. Puoi scorrere l'elenco dei metodi e scegliere quello che vuoi per nome. Se questo sia robusto o una buona idea è un'altra domanda.

+0

Grazie, sapevo di questo ma non volevo ricorrere ad esso. Potrei doverlo fare, però. –

2

Vedere java.beans.Expression e java.beans.Statement.

Problemi correlati