Подтвердить что ты не робот

Конструктор вызовов Java Reflection с примитивными типами

У меня есть метод в моей тестовой среде, который создает экземпляр класса, в зависимости от параметров, переданных в:

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

Проблема заключается в том, что это не работает, если конструктор имеет примитивные типы:

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

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

Результаты в:

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

Примитивные ints автоматически помещаются в объектные версии, но как мне их вернуть для вызова конструктора?

4b9b3361

Ответ 1

Используйте Integer.TYPE вместо Integer.class.

В соответствии с Javadocs это "экземпляр класса, представляющий примитивный тип int".

Вы также можете использовать int.class. Это ярлык для Integer.TYPE. Не только классы, даже для примитивных типов, вы можете сказать type.class в Java.

Ответ 2

Для ссылки на примитивные типы используйте, например:

Integer.TYPE;

Вам нужно будет знать, какие аргументы, переданные в ваш метод, являются примитивными значениями. Вы можете сделать это с помощью:

object.getClass().isPrimitive()

Ответ 3

Так как примитивные типы автобоксированы, вызов getConstructor(java.lang.Class<?>... parameterTypes) завершится с ошибкой. Вам нужно будет вручную прокрутить доступные конструкторы. Если все типы совпадают, вы в порядке. Если некоторые типы не совпадают, но требуемый тип является примитивным И доступным типом является соответствующий класс-оболочка, тогда вы можете использовать этот конструктор. См. Ниже:

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

Ответ 4

вы можете написать

int[].class.getComponentType()

или

Integer.TYPE

или

int.class

Ответ 5

Если примитивное значение int автобоксируется в объект Integer, оно больше не является примитивным. Вы не можете указать из экземпляра Integer, был ли он int в какой-то момент.

Я бы предложил передать два массива в метод test: один с типами и другой со значениями. Он также устранит двусмысленность, если у вас есть конструктор MyClass(Object) и значение строки передачи (getConstructor будет искать конструктор String).
Кроме того, вы не можете определить ожидаемый тип параметра, если значение параметра равно null.