webentwicklung-frage-antwort-db.com.de

Java Reflection-Aufrufkonstruktor mit primitiven Typen

In meinem Testframework gibt es eine Methode, die abhängig von den übergebenen Parametern eine Instanz einer Klasse erstellt:

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, dass dies nicht funktioniert, wenn der Konstruktor wie folgt primitive Typen hat:

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)

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

43
Steve

Verwenden Sie Integer.TYPE anstelle von Integer.class.

Gemäß den 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 einfache Typen können Sie in Java type.class sagen.

129
Andrzej Doyle

Um auf Primitivtypen zu verweisen, verwenden Sie zum Beispiel:

Integer.TYPE;

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

object.getClass().isPrimitive()
18
Plaudit Design

Da die primitiven Typen autoboxiert sind, schlägt der Aufruf von 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, der erforderliche Typ jedoch ein Primitiv ist 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));
}
6
Jake

du kannst schreiben

int[].class.getComponentType()

oder

Integer.TYPE

oder

int.class
3
user3896501

Wenn der primitive int-Wert in das Integer-Objekt autoboxed wird, ist er nicht mehr primitiv. Sie können der Integer-Instanz nicht entnehmen, ob es zu einem bestimmten Zeitpunkt int war. 

Ich würde vorschlagen, zwei Arrays in die test-Methode zu übergeben: eines mit Typen und eines mit Werten. Es wird auch die Mehrdeutigkeit aufheben, wenn Sie einen Konstruktor MyClass(Object) haben und den Stringwert übergeben (getConstructor würde nach String-Konstruktor suchen).
Sie können den erwarteten Parametertyp auch nicht angeben, wenn der Parameterwert null ist.

2
Nikita Rybak

Um zu überprüfen, ob ein Typ ein Primitiv ist oder sein Wrapper, verwenden Sie:

ClassUtils.isPrimitiveOrWrapper(memberClazz)

Wenn Sie prüfen möchten, ob es sich um einen bestimmten Typ handelt, sehen Sie sich Folgendes an:

https://stackoverflow.com/a/27400967/2739334

Auf jeden Fall hatte @Andrzej Doyle vollkommen recht!

0
Code.IT