2010-10-13 20 views
39

ich eine Methode in meinem Test-Framework, die eine Instanz einer Klasse erstellt, in Abhängigkeit von den übergebenen Parametern in:Java Reflection Aufruf Konstruktor mit primitiven Typen

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

Das Problem ist, funktioniert das nicht, wenn der Konstruktor hat primitive Typen wie folgt:

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

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

Ergebnisse in:

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

Th Die primitiven Ints werden in Objektversionen automatisch eingereiht, aber wie bekomme ich sie zum Aufruf des Konstruktors zurück?

Antwort

121

Verwenden Sie Integer.TYPE anstelle von Integer.class.

Gemäß der Javadocs ist dies "Die Klasseninstanz, die den primitiven Typ int darstellt."

Sie können auch int.class verwenden. Es ist eine Abkürzung für Integer.TYPE. Nicht nur Klassen, auch für primitive Typen kann man in Java type.class sagen.

+10

int.class schreiben kann, ist eine Abkürzung für Integer.TYPE, für jede, auch primitiver Typ in Java können Sie schreiben: type.class – iirekm

+1

Das soll eine akzeptierte Antwort sein. Du hast Plaudit Design um ein paar Sekunden besiegt ;-) Gerade bearbeitet, um Iirekms Kommentar hinzuzufügen. –

18

Um primitive Typen verwenden, zum Beispiel Referenz:

Integer.TYPE; 

Sie müssen wissen, was in Ihrer Methode übergebenen Argumente sind primitive Werte. Sie können dies tun mit:

object.getClass().isPrimitive() 
2

Wenn primitive int Wert in Integer Objekt autoboxed wird, ist es nicht mehr primitiv ist. Sie können nicht von Integer Instanz feststellen, ob es an einem bestimmten Zeitpunkt int war.

Ich würde vorschlagen, zwei Arrays in test Methode übergeben: eins mit Typen und ein anderes mit Werten. Es wird auch Mehrdeutigkeit entfernen, wenn Sie einen Konstruktor haben MyClass(Object) und übergeben Zeichenfolge Wert (getConstructor würde nach String Konstruktor suchen).
Sie können den erwarteten Parametertyp auch nicht angeben, wenn der Parameterwert null ist.

+0

'Wenn primitive int-Wert in Integer-Objekt autoboxed ist, ist es nicht mehr primitiv. Sie können nicht von der Integer-Instanz unterscheiden, ob sie zu irgendeinem Zeitpunkt int war. Sie haben diesen Punkt mit der gestellten Frage nicht erhalten. Wenn ein Primitiv in Integer eingerahmt ist, dann wird es nicht zu var args aufgelöst –

+0

@ org.life.java Was meinst du mit _ "löst nicht zu var args" _? Der Fehler liegt daran, dass der Konstruktor nicht gefunden werden kann. Vararg-Teil funktioniert reibungslos, _int_ wird in _Integer_ für zweite und dritte Elemente von _constructorArgs_ array konvertiert (aus dem einfachen Grund, dass _int_ nicht Teil von _Object [] _ ​​sein kann). –

+0

ow ... Entschuldigung missverstanden Frage. noch Q. ist unklar :) –

4

Da die primitiven Typen autoboxiert sind, schlägt der Aufruf getConstructor(java.lang.Class<?>... parameterTypes) fehl. Sie müssen die verfügbaren Konstruktoren manuell durchlaufen. Wenn alle Typen übereinstimmen, geht es Ihnen gut. Wenn einige Typen nicht übereinstimmen, aber der erforderliche Typ ein primitiver UND der verfügbare Typ die entsprechende Wrapper-Klasse ist, können Sie diesen Konstruktor verwenden. Siehe unten:

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

Sie haben die Fließkommatypen vergessen. – Lii

3

Sie

int[].class.getComponentType() 

oder

Integer.TYPE 

oder

int.class 
+0

für einfache und klare Antwort – nahab

Verwandte Themen