2010-10-13 17 views
39

Ho un metodo nel mio quadro di prova che crea un'istanza di una classe, a seconda dei parametri passati in:Java Reflection chiamando costruttore con i tipi primitivi

public void test(Object... constructorArgs) throws Exception { 
    Constructor<T> con; 
    if (constructorArgs.length > 0) { 
     Class<?>[] parameterTypes = new Class<?>[constructorArgs.length]; 
     for (int i = 0; i < constructorArgs.length; i++) { 
      parameterTypes[i] = constructorArgs[i].getClass(); 
     } 
     con = clazz.getConstructor(parameterTypes); 
    } else { 
     con = clazz.getConstructor(); 
    } 
} 

Il problema è che questo non funziona se il costruttore ha tipi primitivi, come segue:

public Range(String name, int lowerBound, int upperBound) { ... } 

.test("a", 1, 3); 

risultati in:

java.lang.NoSuchMethodException: Range.<init>(java.lang.String, java.lang.Integer, java.lang.Integer) 

Th Gli inte primitivi sono auto-inscatolati nelle versioni degli oggetti, ma come ottenerli per chiamare il costruttore?

risposta

121

Utilizzare Integer.TYPE anziché Integer.class.

Come per lo Javadocs, questo è "L'istanza di classe che rappresenta il tipo primitivo int".

È inoltre possibile utilizzare int.class. È una scorciatoia per Integer.TYPE. Non solo le classi, anche per i tipi primitivi, puoi dire type.class in Java.

+10

int.class è una scorciatoia per Integer.TYPE, per qualsiasi, anche tipo primitivo in Java puoi scrivere: type.class – iirekm

+1

Questa dovrebbe essere una risposta accettata. Hai battuto Plaudit Design di pochi secondi ;-) Modificato per includere il commento di iirekm. –

18

Per riferimento tipi primitivi utilizzare, ad esempio:

Integer.TYPE; 

Avrete bisogno di sapere quali argomenti passati nel vostro metodo sono valori primitivi. Si può fare questo con:

object.getClass().isPrimitive() 
2

Se primitivo valore int è autoboxed in Integer oggetto, non è più primitiva. Non è possibile sapere dall'istanza Integer se era int ad un certo punto.

Suggerirei di passare due array nel metodo test: uno con tipi e un altro con valori. Rimuoverà anche l'ambiguità se hai un costruttore MyClass(Object) e passa il valore stringa (getConstructor cercherebbe il costruttore String).
Inoltre, non è possibile indicare il tipo di parametro previsto se il valore del parametro è nullo.

+0

'se il valore int primitivo è autoboxed nell'oggetto Integer, non è più primitivo. Non puoi dire dall'istanza di Integer se era int a un certo punto. Non hai ottenuto questo punto con la domanda posta. se un primitivo è inscatolato in numero intero che il motivo per cui non viene risolto a var args –

+0

@ org.life.java Cosa vuoi dire, _ "non risolve a args var" _? L'errore è dovuto al fatto che il costruttore non può essere trovato. Vararg parte funziona uniformemente, _int_ viene convertito in _Integer_ per secondo e terzo elemento di matrice _constructorArgs_ (per la semplice ragione che _int_ non può ba una parte di _Object [] _). –

+0

ow ... Mi spiace frainteso Domanda. ancora Q. non è chiaro :) –

4

Poiché i tipi primitivi sono autoboxed, la chiamata getConstructor(java.lang.Class<?>... parameterTypes) avrà esito negativo. Sarà necessario scorrere manualmente i costruttori disponibili. Se tutti i tipi corrispondono, allora stai bene. Se alcuni tipi non corrispondono, ma il tipo richiesto è un primitivo E il tipo disponibile è la classe wrapper corrispondente, è possibile utilizzare tale costruttore. Vedi sotto:

static <C> Constructor<C> getAppropriateConstructor(Class<C> c, Object[] initArgs){ 
    if(initArgs == null) 
     initArgs = new Object[0]; 
    for(Constructor con : c.getDeclaredConstructors()){ 
     Class[] types = con.getParameterTypes(); 
     if(types.length!=initArgs.length) 
      continue; 
     boolean match = true; 
     for(int i = 0; i < types.length; i++){ 
      Class need = types[i], got = initArgs[i].getClass(); 
      if(!need.isAssignableFrom(got)){ 
       if(need.isPrimitive()){ 
        match = (int.class.equals(need) && Integer.class.equals(got)) 
        || (long.class.equals(need) && Long.class.equals(got)) 
        || (char.class.equals(need) && Character.class.equals(got)) 
        || (short.class.equals(need) && Short.class.equals(got)) 
        || (boolean.class.equals(need) && Boolean.class.equals(got)) 
        || (byte.class.equals(need) && Byte.class.equals(got)); 
       }else{ 
        match = false; 
       } 
      } 
      if(!match) 
       break; 
     } 
     if(match) 
      return con; 
    } 
    throw new IllegalArgumentException("Cannot find an appropriate constructor for class " + c + " and arguments " + Arrays.toString(initArgs)); 
} 
+0

Hai dimenticato i tipi a virgola mobile. – Lii

3

è possibile scrivere

int[].class.getComponentType() 

o

Integer.TYPE 

o

int.class 
+0

per una risposta semplice e chiara – nahab

Problemi correlati