2010-10-13 8 views
39

у меня есть метод в моей тестовой структуре, которая создает экземпляр класса, в зависимости от параметров, переданных в: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) 

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

ответ

121

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

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

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

+10

int.class ярлык для Integer.TYPE, для любого, даже примитивный тип в Java вы можете написать: type.class – iirekm

+1

Предполагается, что это будет принятый ответ. Вы избили Plaudit Design на несколько секунд ;-) Просто отредактирован, чтобы включить комментарий iirekm. –

18

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

Integer.TYPE; 

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

object.getClass().isPrimitive() 
2

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

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

+0

', если значение примитивного значения int автобоксации в объект Integer, оно больше не является примитивным. Вы не можете указать из экземпляра Integer, был ли он int в какой-то момент, не получил ваш вопрос с заданным вопросом. если примитив помечен в поле Integer, чем почему он не разрешает var args –

+0

@ org.life.java Что значит, _ «не разрешает var args» _? Ошибка заключается в том, что конструктор не найден. Параметр Vararg работает гладко, _int_ преобразуется в _Integer_ для второго и третьего элементов массива _constructorArgs_ (по той простой причине, что _int_ не может быть частью _Object [] _). –

+0

ow ... Извините неправильно понятый вопрос. еще Q. неясно :) –

4

Поскольку примитивные типы являются автобоксами, вызов 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)); 
} 
+0

Вы забыли типы с плавающей запятой. – Lii

3

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

int[].class.getComponentType() 

или

Integer.TYPE 

или

int.class 
+0

для простого и ясного ответа – nahab

Смежные вопросы