Este artículo describe en detalle el mecanismo de reflexión de Java en forma de ejemplos, que es una habilidad importante en la programación Java. Compártelo con todos para tu referencia. El análisis específico es el siguiente:
En primer lugar, Reflection es una de las características del lenguaje de desarrollo de programas Java. Permite que el programa Java en ejecución se verifique a sí mismo o se "autoaudite" y opere directamente las propiedades internas del programa . Por ejemplo, utilícelo para obtener el nombre de cada miembro de una clase Java y mostrarlo. Es posible que esta capacidad de Java no se utilice mucho en aplicaciones prácticas, pero esta característica no existe en absoluto en otros lenguajes de programación. Por ejemplo, en Pascal, C o C++ no hay forma de obtener información sobre las definiciones de funciones en el programa.
JavaBean es una de las aplicaciones prácticas de la reflexión, que permite que algunas herramientas operen visualmente componentes de software. Estas herramientas cargan y obtienen dinámicamente las propiedades de los componentes (clases) de Java a través de la reflexión.
1. Un ejemplo sencillo
Considere el siguiente ejemplo sencillo y veamos cómo funciona la reflexión.
importar java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName("java.util.Stack" Method m[] = c.getDeclaredMethods (); para (int i = 0; i < m.length; i++) System.out.println(m[i].toString() } catch (Throwable). mi){ System.err.println(e);
Su resultado es:
público sincronizado java.lang.Object java.util.Stack.pop() público java.lang.Object java.util.Stack.push(java.lang.Object)público booleano java.util.Stack.empty() público sincronizado java .lang.Object java.util.Stack.peek() público sincronizado int java.util.Stack.search(java.lang.Object)
Esto enumera los nombres de los métodos de la clase java.util.Stack junto con sus calificadores y tipos de retorno.
Este programa usa Class.forName para cargar la clase especificada y luego llama a getDeclaredMethods para obtener la lista de métodos definidos en la clase. java.lang.reflect.Methods es una clase utilizada para describir un único método en una clase.
2. Comience a usar Reflexión
Las clases de reflexión, como Método, se pueden encontrar en el paquete java.lang.relfect. Hay tres pasos que debes seguir al usar estas clases: El primer paso es obtener el objeto java.lang.Class de la clase que deseas operar. En un programa Java en ejecución, la clase java.lang.Class se utiliza para describir clases, interfaces, etc.
La siguiente es una de las formas de obtener un objeto Clase:
Clase c = Class.forName("java.lang.String");
Esta declaración obtiene un objeto de clase de la clase String. Hay otra manera, como la siguiente declaración:
Clase c = int.class; o Clase c = Integer.TYPE;
Obtienen información de clase para tipos básicos. El último método accede al campo TIPO predefinido en la clase de encapsulación de tipo básico (como Integer).
El segundo paso es llamar a un método como getDeclaredMethods para obtener una lista de todos los métodos definidos en la clase.
Una vez obtenida esta información, puede continuar con el tercer paso: utilizar la API de reflexión para operar esta información, como el siguiente código:
Clase c = Class.forName("java.lang.String"); Método m[] = c.getDeclaredMethods(); System.out.println(m[0].toString());
Imprimirá textualmente el prototipo del primer método definido en String.
En el siguiente ejemplo, estos tres pasos ilustran el uso de la reflexión para una aplicación particular.
Simular el operador de instancia
Después de obtener la información de la clase, normalmente el siguiente paso es resolver algunas preguntas básicas sobre el objeto Clase. Por ejemplo, el método Class.isInstance se puede utilizar para simular el operador instancia de:
clase S { } clase pública IsInstance { public static void main(String args[]) { try { Class cls = Class.forName("S"); .println(b1); booleano b2 = cls.isInstance(new S()); (E arrojable) { System.err.println(e);
En este ejemplo, se crea un objeto Class de clase S y luego se verifican algunos objetos para ver si son instancias de S. Integer(37) no lo es, pero el nuevo S() sí lo es.
3. Encuentra el método de la clase.
Descubrir qué métodos están definidos en una clase es un uso de reflexión básico y muy valioso. El siguiente código implementa este uso:
import java.lang.reflect.*; clase pública Método1 {privado int f1(Objeto p, int x) lanza NullPointerException {if (p == nulo) lanza nueva NullPointerException(); public static void main(String args); []) { intentar { Clase cls = Class.forName("Método1"); Método methlist[] = cls.getDeclaredMethods(); for (int i = 0; i < methlist.length; i++) { Método m = methlist[i]; System.out.println("nombre = " + m.getName()); class = " + m.getDeclaringClass()); Clase pvec[] = m.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Clase evec[] = m.getExceptionTypes(); for (int j = 0; j < evec.length; j++) System. out.println("exc #" + j + " " + evec[j]); System.out.println("tipo de retorno = " + m.getReturnType()); System.out.println("-----"); } } catch (E arrojable) { System.err.println(e);
Este programa primero obtiene la descripción de la clase método1 y luego llama a getDeclaredMethods para obtener una serie de objetos Método, que describen cada método definido en la clase, incluidos métodos públicos, métodos protegidos, métodos de paquete y métodos privados. Si usa getMethods en lugar de getDeclaredMethods en su programa, también puede obtener información sobre cada método heredado.
Después de obtener la lista de objetos del método, no es difícil mostrar los tipos de parámetros, tipos de excepción, tipos de valores de retorno, etc. de estos métodos. Ya sea que estos tipos sean tipos primitivos o tipos de clase, pueden ordenarse mediante los objetos que describen la clase.
Los resultados de salida son los siguientes:
nombre = f1 decl clase = clase método1 parámetro #0 clase java.lang.Object parámetro #1 int exc #0 clase java.lang.NullPointerException tipo de retorno = int-----nombre = principal decl clase = clase método1 parámetro #0 clase [Ljava.lang.String; tipo de retorno = vacío
4. Obtenga información del constructor
El uso de obtener el constructor de clase es similar al uso del método de obtención anterior, como por ejemplo:
import java.lang.reflect.*;public class Constructor1 { public Constructor1() { } protected Constructor1(int i, double d) { } public static void main(String args[]) { try { Class cls = Class.forName( "Constructor1"); Constructor ctorlist[] = cls.getDeclaredConstructors(); para (int i = 0; i < ctorlist.length; i++) { Constructor ct = ctorlist[i]; System.out.println("nombre = " + ct.getName()); System.out.println("decl clase = " + ct.getDeclaringClass()); [] = ct.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Clase evec[] = ct.getExceptionTypes(); para (int j = 0; j < evec.length; j++) System.out.println("exc #" + j + " " + evec[j]); System.out.println("-----"); } } catch (Lanzable e) { System.err.println(e); }
En este ejemplo, no se puede obtener información sobre el tipo de retorno porque el constructor no tiene un tipo de retorno.
El resultado de ejecutar este programa es:
nombre = Constructor1decl clase = clase Constructor1param #0 intparam #1 doble-----nombre = Constructor1decl clase = clase Constructor1-----
5. Obtener los campos (dominios) de la clase.
También es posible saber qué campos de datos están definidos en una clase, como lo hace el siguiente código:
importar java.lang.reflect.*; public class Field1 {privado doble d; public static final int i = 37; String s = "testing"; public static void main(String args[]) {try { Class cls = Class. forName("Campo1"); Campo lista de campos[] = cls.getDeclaredFields(); para (int i = 0; i < lista de campos.length; i++) { Campo fld = lista de campos[i]; System.out.println("nombre = " + fld.getName()); System.out.println("decl clase = " + fld.getDeclaringClass()); = " + fld.getType()); int mod = fld.getModifiers(); System.out.println("modificadores = " + Modifier.toString(mod)); System.out.println("-----"); } } catch (E arrojable) { System.err.println(e);
Este ejemplo es muy similar al anterior. En este ejemplo, se usa un modificador de cosa nueva, que también es una clase de reflexión y se usa para describir los modificadores de miembros de campo, como "private int". Los modificadores mismos se describen mediante números enteros, y Modifier.toString se utiliza para devolver las descripciones de las cadenas en orden "oficial" (por ejemplo, "estático" antes de "final"). El resultado de este programa es:
nombre = ddecl clase = clase Campo1tipo = doublemodifiers = privado-----nombre = idecl clase = clase Campo1tipo = intmodifiers = public static final-----nombre = sdecl clase = clase Campo1tipo = clase java.lang.Stringmodifiers = - ----
Al igual que con el método get, al obtener campos, también puede obtener solo la información del campo declarado en la clase actual (getDeclaredFields), o también puede obtener los campos definidos en la clase principal (getFields).
6. Ejecutar el método según su nombre.
En este punto del texto, todos los ejemplos dados están relacionados con cómo obtener información de clase. También podemos usar la reflexión para hacer otras cosas, como ejecutar un método con un nombre específico. El siguiente ejemplo demuestra esta operación:
importar java.lang.reflect.*; public class Method2 { public int add(int a, int b) { return a + b } public static void main(String args[]) { try { Class cls = Class.forName( "Método2"); Clase partypes[] = nueva Clase[2]; partypes[0] = Integer.TYPE; cls.getMethod("add", partypes); Método2 methobj = nuevo Método2(); Objeto arglist[] = nuevo Objeto[2]; nuevo Integer(37) = new Integer(47); ); Objeto retobj = meth.invoke(methobj, arglist); Entero retval = (Entero) retobj; System.out.println(retval.intValue()); captura (tirable e) { System.err.println(e);
Si un programa solo sabe que un determinado método debe ejecutarse en algún lugar durante la ejecución y el nombre de este método se especifica durante la ejecución del programa (por ejemplo, esto se hace en el entorno de desarrollo JavaBean), entonces el programa anterior demuestra cómo hacerlo.
En el ejemplo anterior, getMethod se utiliza para buscar un método llamado add que tiene dos parámetros enteros. Después de encontrar el método y crear el objeto Método correspondiente, ejecútelo en la instancia de objeto correcta. Al ejecutar este método, debe proporcionar una lista de parámetros, que en el ejemplo anterior son dos objetos Integer que envuelven los números enteros 37 y 47 respectivamente. El método de ejecución devuelve un objeto Integer, que encapsula el valor de retorno 84.
7. Crea nuevos objetos
Para los constructores, no se puede proceder como la ejecución de métodos, porque ejecutar un constructor significa crear un nuevo objeto (para ser precisos, el proceso de creación de un objeto incluye asignar memoria y construir el objeto). Entonces, el ejemplo más similar al ejemplo anterior es el siguiente:
importar java.lang.reflect.*; public class Constructor2 { public Constructor2() { } public Constructor2(int a, int b) { System.out.println("a = " + a + " b = " + b); } public static void main(String args[]) { prueba { Class cls = Class.forName("Constructor2 Class partypes[] = new Class[2]; partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Constructor ct = cls.getConstructor(partypes); Objeto arglist[] = nuevo Objeto[2]; arglist[1] = new Integer(47); Objeto retobj = ct.newInstance(arglist } catch); (E arrojable) { System.err.println(e);
Encuentre el constructor correspondiente según los tipos de parámetros especificados y ejecútelo para crear una nueva instancia de objeto. El uso de este enfoque le permite crear objetos dinámicamente mientras el programa se está ejecutando en lugar de en el momento de la compilación, lo cual es muy valioso.
8. Cambiar el valor de un campo (dominio)
Otro uso de la reflexión es cambiar los valores de los campos de datos del objeto. Reflection puede encontrar los campos de un objeto por nombre desde un programa en ejecución y cambiarlo. El siguiente ejemplo ilustra esto:
importar java.lang.reflect.*; public class Field2 { public double d; public static void main(String args[]) { try { Class cls = Class.forName("Field2"); d"); Campo2 f2obj = nuevo Campo2(); System.out.println("d = " + f2obj.d); fld.setDouble(f2obj, 12.34); System.out.println("d = " + f2obj.d } catch (E arrojable) { System.err.println(e);
En este ejemplo, el valor del campo d se cambia a 12,34.
9. Utilice matrices
El uso final de la reflexión presentado en este artículo es la creación de matrices de operandos. Una matriz es un tipo de clase especial en el lenguaje Java y se puede asignar una referencia de matriz a una referencia de objeto. Mire el siguiente ejemplo para ver cómo funcionan las matrices:
importar java.lang.reflect.*; public class Array1 { public static void main(String args[]) { intentar { Class cls = Class.forName("java.lang.String Object arr = Array.newInstance(cls"); , 10); Array.set(arr, 5, "esto es una prueba"); String s = (String) Array.get(arr, 5); System.out.println(s); } catch (E arrojable) { System.err.println(e);
En el ejemplo, se crea una matriz de cadenas de 10 unidades de longitud, se asigna un valor a la cadena en la quinta posición y, finalmente, la cadena se obtiene de la matriz y se imprime.
El siguiente código proporciona un ejemplo más complejo:
import java.lang.reflect.*; public class Array2 { public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; TIPO, atenuaciones); Objeto arrobj = Array.get(arr, 3); arrobj.getClass().getComponentType(); System.out.println(cls); arrobj = Array.get(arrobj, 5); Array.setInt(arrobj, 10, 37); (int[][][]) arr; System.out.println(arrcast[3][5][10]);
En el ejemplo, se crea una matriz de enteros de 5 x 10 x 15 y al elemento en [3][5][10] se le asigna el valor 37. Tenga en cuenta que las matrices multidimensionales son en realidad matrices de matrices, por ejemplo, después del primer Array.get, arrobj es una matriz de 10 x 15. Luego obtenga uno de los elementos, es decir, una matriz con una longitud de 15, y use Array.setInt para asignar un valor a su décimo elemento.
Tenga en cuenta que el tipo de matriz cuando se crea es dinámico y su tipo no se conoce en el momento de la compilación .
Creo que lo que describe este artículo tiene cierto valor de referencia para el aprendizaje de la programación Java por parte de todos.