2010-04-08 27 views
22

Pregunta simple, ¿cómo funciona este código?Cómo trabajar con varargs y reflexión

public class T { 

    public static void main(String[] args) throws Exception { 
     new T().m(); 
    } 

    public // as mentioned by Bozho 
    void foo(String... s) { 
     System.err.println(s[0]); 
    } 

    void m() throws Exception { 
     String[] a = new String[]{"hello", "kitty"}; 
     System.err.println(a.getClass()); 
     Method m = getClass().getMethod("foo", a.getClass()); 
     m.invoke(this, (Object[]) a); 
    } 
} 

Salida:

class [Ljava.lang.String; 
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 

Respuesta

41
Test.class.getDeclaredMethod("foo", String[].class); 

obras. El problema es que getMethod(..) solo busca los métodos public. Desde el javadoc:

Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object.

Actualización: Después de conseguir con éxito el método, se puede invocar usando:

m.invoke(this, new Object[] {new String[] {"a", "s", "d"}}); 

que es - crear una nueva Object matriz con un elemento - la matriz String. Con los nombres de las variables que se vería así:

m.invoke(this, new Object[] {a}); 
+0

Gracias! Pero ahora me atrapan la invocación. – PeterMmm

+0

¡Gracias de nuevo! No viste eso. – PeterMmm

+0

+1 para la solución 'invoke'; eso es desagradable. – polygenelubricants

8

// antes de editar:

Su problema es el hecho de que getMethod busca un miembro de public.

Desde el (el énfasis es mío) Class.getMethod:

Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object

lo que tiene dos opciones:

  • Make public void foo(String... s) y utilizar getMethod
  • Uso getDeclaredMethod lugar

Tenga en cuenta que la misma diferencia existe para r getField/s vs getDeclaredField/s y getConstructor/s contra getDeclaredConstructor/s.


// invoke problema

Esto es particularmente desagradable, pero lo que sucede es que invoke(Object obj, Object... args) hace que sea difícil si usted necesita para pasar una matriz de tipo de referencia como un único argumento, porque se echa-poder a Object[], a pesar de que debería estar envuelto dentro de un new Object[1] en su lugar.

que puede hacer:

m.invoke(this, new Object[] {a}); // Bohzo's solution 

Esto no pasa por el mecanismo de vararg. Más sucintamente también se puede hacer:

m.invoke(this, (Object) a); 

El reparto de Object hace que el mecanismo de vararg hacer el trabajo de crear la matriz para usted.

El truco también es necesario cuando se pasa un null como argumento para varargs, y no tiene nada que ver con la reflexión.

public void foo(String... ss) { 
    System.out.println(ss[0]); 
} 

    foo(null); // causes NullPointerException 
    foo((String) null); // prints "null" 
+1

+1, bueno para este elenco cosa – PeterMmm

+0

@polygenelubricants, mi caso es: void foo() función tiene argumento Param ... param (Sugerencia: Param es de tipo genérico) en lugar de String ... s. Utilicé el nuevo Object [] {new URL ("google.com")}, pero aparece el siguiente error: IllegalArgumentException: el argumento 1 debe tener java.lang.Object [], tiene java.net.URL. Gracias de antemano. – MapleLover

Cuestiones relacionadas