varargs vararg java reflection variadic-functions

java - varargs - vararg kotlin



Cómo trabajar con varargs y reflexión (2)

Pregunta simple, ¿cómo funciona este código?

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)


// antes de la edición:

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

Del Class.getMethod (énfasis mío):

Devuelve un objeto Method que refleja el método miembro público especificado de la clase o interfaz representada por este objeto Clase

Así que tienes dos opciones:

  • Hacer public void foo(String... s) y usar getMethod
  • Use getDeclaredMethod en getDeclaredMethod lugar

Tenga en cuenta que existe la misma diferencia para getField/s frente a getDeclaredField/s getConstructor/s frente a getDeclaredConstructor/s .

// invoke problema

Esto es particularmente desagradable, pero lo que sucede es que invoke(Object obj, Object... args) hace complicado si necesita pasar una matriz de tipo de referencia como un único argumento, porque es apto para Object[] , a pesar de que debería estar envuelto dentro de un new Object[1] lugar.

Tu puedes hacer:

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

Esto pasa por alto el mecanismo vararg. Más sucintamente, también puedes hacer:

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

La conversión a Object hace que el mecanismo vararg haga el trabajo de crear la matriz para ti.

El truco también se necesita al pasar un null como argumento a 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"


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

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

Devuelve un objeto Método que refleja el método miembro público especificado de la clase o interfaz representada por este objeto Clase.

Actualización: después de obtener el método con éxito, puede invocarlo usando:

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

es decir, crea una nueva matriz de Object con un elemento: la matriz de String . Con sus nombres de variable se vería así:

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