Вызывающий конструктор Java Reflection с примитивными типами - PullRequest
46 голосов
/ 13 октября 2010

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

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)

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

Ответы [ 6 ]

137 голосов
/ 13 октября 2010

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

Согласно Javadocs , это «Экземпляр класса, представляющий тип примитива int

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

19 голосов
/ 13 октября 2010

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

Integer.TYPE;

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

object.getClass().isPrimitive()
6 голосов
/ 09 августа 2013

Поскольку примитивные типы автоматически упакованы, вызов 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));
}
3 голосов
/ 15 декабря 2015

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

int[].class.getComponentType()

или

Integer.TYPE

или

int.class
2 голосов
/ 13 октября 2010

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

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

0 голосов
/ 06 сентября 2018

Чтобы на самом деле проверить, является ли тип примитивом или его оболочкой, используйте:

ClassUtils.isPrimitiveOrWrapper(memberClazz)

В случае, если вы хотите проверить, является ли тип определенным типом, посмотрите на это:

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

В любом случае @Andrzej Doyle был полностью прав!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...