2010-10-13 14 views
39

que tengo un método en mi marco de pruebas que crea una instancia de una clase, dependiendo de los parámetros pasados ​​en:Java Reflexión con los tipos primitivos

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

El problema es que esto no funciona si el constructor tiene tipos primitivos, de la siguiente manera:

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

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

resultados en:

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

Th Las entradas primitivas están encasilladas automáticamente en versiones de objeto, pero ¿cómo puedo recuperarlas para llamar al constructor?

Respuesta

121

Use Integer.TYPE en lugar de Integer.class.

Según el Javadocs, esta es "La instancia de clase que representa el tipo primitivo int".

También puede usar int.class. Es un atajo para Integer.TYPE. No solo las clases, incluso para los tipos primitivos puede decir type.class en Java.

+10

int.class es un atajo para Integer.TYPE, para cualquier, incluso tipo primitivo en Java puede escribir: type.class – iirekm

+1

Se supone que es una respuesta aceptada. Ganaste a Plaudit Design por unos segundos ;-) Recién editado para incluir el comentario de iirekm. –

18

Para referencia uso de tipos primitivos, por ejemplo:

Integer.TYPE; 

Usted necesitará saber qué argumentos pasados ​​en su método son valores primitivos. Usted puede hacer esto con:

object.getClass().isPrimitive() 
2

Si primitiva valor int se autoboxed en Integer objeto, no es primitiva más. No se puede decir desde la instancia Integer si fue int en algún momento.

Sugeriría pasar dos matrices en el método test: una con tipos y otra con valores. También eliminará la ambigüedad si tiene un constructor MyClass(Object) y pasa el valor de cadena (getConstructor estaría buscando el constructor String).
Además, no puede indicar el tipo de parámetro esperado si el valor del parámetro es nulo.

+0

'si el valor int primitivo se autoboxea en el objeto Integer, ya no es primitivo. No se puede decir desde la instancia de Integer si fue int en algún momento 'no entendí su punto con la pregunta. si una primitiva está encuadrada en Entero de por qué no se resuelve en var args –

+0

@ org.life.java ¿Qué quiere decir que _ "no se resuelve en var args" _? El error es porque el constructor no se puede encontrar. La parte Vararg funciona sin problemas, _int_ se convierte en _Integer_ para el segundo y tercer elemento de _constructorArgs_ array (por la sencilla razón de que _int_ no puede formar parte de _Object [] _). –

+0

ow ... Lo siento mal entendido Pregunta. aún Q. no está claro :) –

4

Dado que los tipos primitivos se autoboxan, la llamada getConstructor(java.lang.Class<?>... parameterTypes) fallará. Tendrá que recorrer manualmente los constructores disponibles. Si todos los tipos coinciden, entonces estás bien. Si algunos tipos no coinciden, pero el tipo requerido es un primitivo Y el tipo disponible es la clase contenedora correspondiente, entonces puede usar ese constructor. Ver abajo:

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

Olvidó los tipos de coma flotante. – Lii

3

se puede escribir

int[].class.getComponentType() 

o

Integer.TYPE 

o

int.class 
+0

para una respuesta simple y clara – nahab

Cuestiones relacionadas