Introducción
De acuerdo con la Real Academia de la Lengua Española, reflexión(1) es la "Acción y efecto de reflexionar", en tanto que reflexionar(2) es: "Considerar nueva o detenidamente algo".
Wikipedia menciona la reflexión en informática(3) como "la capacidad que tiene un programa de ordenador para observar y opcionalmente modificar su estructura de alto nivel".
Definición
En mis propios términos:
La reflexión en la programación de Software es la característica de un lenguaje que permite conocer su estructura de manera dinámica (en tiempo de ejecución).
Ejemplo:
A continuación se muestra un ejemplo que tiene la siguiente funcionalidad:
- Crear una clase del tipo que se proporcione en el primer parámetro.
- Crear un objeto a partir de la clase creada en el punto anterior.
- Obtener el valor de la propiedad indicada en el segundo parámetro.
- Modificar el valor de la propiedad que se obtuvo en el punto anterior con el valor del tercer parámetro.
Versión Java:
Antes de efectuar el ejemplo es necesario:
- Tener la JDK versión >= 1.5 instalada (4)
- Saber compilar y ejecutar clases Java (5).
El ejemplo EjemploReflexion funciona con cualquier clase. La única restricción (por sencillez en la programación) es que la propiedad a modificar sea de tipo java.lang.String.
Para simplificar aún más la prueba se proporciona también la clase Cliente.
Para ejecutar el ejemplo solo es necesario compilar ambas clases y ejecutarlas mediante el comando:
java EjemploReflexion org.josuemb.Cliente nombre Josue
En caso de que se desee ejecutar el ejemplo con otra clase, la sintaxis sería:
java EjemploReflexion NombreClase NombrePropiedad Valor
package org.josuemb; import java.lang.reflect.Field; /** * * Clase que muestra un ejemplo de reflexión. * * @author josuemb * */ public class EjemploReflexion { /** * @param args */ @SuppressWarnings("unchecked") //Evita un warning al compilar public static void main(String[] args) { try { if (args.length < 3) { System.out.println("Error en llamado\n"); System.out.println("Sintaxis:"); System.out .println("\tjava EjemploReflexion NombreClase NombrePropiedad Valor"); System.out.println("Ejemplo:"); System.out .println("\tjava EjemploReflexion org.josuemb.Cliente nombre Josue"); System.exit(1); } System.out.println("Creando clase [" + args[0] + "] de manera dinamica..."); // Crea la clase proporcionada en el primer parámetro de manera // dinámica. Class clase = Class.forName(args[0]); System.out.println("Creando objeto de tipo [" + clase.getName() + "] manera dinámica..."); //Crea un nuevo objeto de manera dinamica Object objeto = clase.newInstance(); System.out.println("Obteniendo propiedad [" + args[1] + "] del nuevo objeto de manera dinamica..."); // Obtiene la propiedad proporcionada en el segundo parámetro de // manera dinámica. Field propiedad = objeto.getClass().getDeclaredField(args[1]); // Es necesario establecer esta propiedad para acceder a los campos // de la clase directamente. propiedad.setAccessible(true); // Obtiene el valor de la propiedad Object valor1 = propiedad.get(objeto); // Imprime el valor de la propiedad System.out.println(propiedad.getName() + "=" + valor1); System.out.println("Modificando valor de propiedad [" + propiedad.getName() + "]..."); //Establece el nuevo valor a la propiedad propiedad.set(objeto, args[2]); // Obtiene el valor de la propiedad Object valor2 = propiedad.get(objeto); // Imprime el valor de la propiedad System.out.println(propiedad.getName() + "=" + valor2); System.exit(0); } catch (Exception e) { e.printStackTrace(); } } }Archivo Cliente.java:
package org.josuemb; public class Cliente { private String nombre; private String lugar; public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public String getLugar() { return lugar; } public void setLugar(String lugar) { this.lugar = lugar; } }
El resultado de la ejecución es el siguiente:
josuemb@josuemb-laptop:~/workspaces/Ejemplos/EjemploReflexion/bin$ java org.josuemb.EjemploReflexion org.josuemb.Cliente nombre Josue Creando clase [org.josuemb.Cliente] de manera dinamica... Creando objeto de tipo [org.josuemb.Cliente] manera dinámica... Obteniendo propiedad [nombre] del nuevo objeto de manera dinamica... nombre=null Modificando valor de propiedad [nombre]... nombre=Josue
Versión Groovy:
Antes de efectuar el ejemplo es necesario:
- Tener la Groovy versión >= 1.7 instalado (6)
- Saber compilar clases Groovy (7).
- Saber ejecutar scripts Groovy (8).
El ejemplo funciona con cualquier clase. La única restricción (por sencillez en la programación) es que la propiedad a modificar sea de tipo java.lang.String.
Para simplificar aún más la prueba se proporciona también la clase Cliente.
Para ejecutar el ejemplo solo es necesario compilar la clase Cliente mediante el comando:
groovyc EjemploReflexion.groovy
Y después ejecutar el Script EjemploReflexion mediante el comando:
groovy EjemploReflexion.groovy org.josuemb.Cliente nombre Josue
En caso de que se desee ejecutar el ejemplo con otra clase, la sintaxis sería:
groovy EjemploReflexion.groovy nombreClase nombrePropiedad Valor
if(args.size() < 3 ){ println """Error en llamado Sintaxis: groovy EjemploReflexion.groovy NombreClase NombrePropiedad Valor Ejemplo: groovy EjemploReflexion.groovy org.josuemb.Cliente nombre Josue""" System.exit 1 } println "Creando clase [${args[0]}] de manera dinamica..." // Crea la clase proporcionada en el primer parámetro de manera dinámica. def clase = args[0] as Class; println "Creando objeto de tipo [$clase.name] de manera dinamica..." //Crea un nuevo objeto de manera dinamica def objeto = clase.newInstance() println "Obteniendo propiedad [${args[1]}] del nuevo objeto de manera dinamica..." println "${args[1]}=${objeto[args[1]]}" //Establece el nuevo valor a la propiedad objeto[args[1]] = args[2] println "Modificando valor de propiedad [${args[1]}]..." objeto[args[1]] = args[2] println "${args[1]}=${objeto[args[1]]}"
Archivo Cliente.groovy:
package org.josuemb class Cliente{ String nombre String lugar }
El resultado de la ejecución es el siguiente:
josuemb@josuemb-laptop:~$ groovy EjemploReflexion.groovy org.josuemb.Cliente nombre Josue Creando clase [org.josuemb.Cliente] de manera dinamica... Creando objeto de tipo [org.josuemb.Cliente] de manera dinamica... Obteniendo propiedad [nombre] del nuevo objeto de manera dinamica... nombre=null Modificando valor de propiedad [nombre]... nombre=Josue
Conclusión
La reflexión nos permite hacer cosas bastante interesantes como por ejemplo: conocer la estructura interna de una clase, sus propiedades, constructores, métodos (parámetros de los mismos), ejecutar los métodos, incluso, ¡obtener y modificar información de miembros privados de una clase! y todo esto aún si no tenemos ni el código ni la documentación de una clase.
Referencias
- Reflexión: http://buscon.rae.es/draeI/SrvltConsulta?TIPO_BUS=3&LEMA=reflexion
- Reflexionar: http://buscon.rae.es/draeI/SrvltConsulta?TIPO_BUS=3&LEMA=reflexionar
- Reflexión Informática: http://es.wikipedia.org/wiki/Reflexi%C3%B3n_%28inform%C3%A1tica%29
- Instalación de la JDK 1.6: http://java.sun.com/javase/6/webnotes/install/index.html
- Compilar y ejecutar clases Java: http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/getStarted/cupojava/index.html
- Instalación de Groovy 1.7: http://groovy.codehaus.org/Tutorial+1+-+Getting+started
- Compilar clases Groovy: http://docs.codehaus.org/display/GROOVY/Compiling+Groovy
- Ejecutar scripts Groovy: http://groovy.codehaus.org/Running
- Artículo "Usando Java Reflection" (Oracle): http://java.sun.com/developer/technicalArticles/ALT/Reflection/
- Artículo "Programación dinámica en Java, parte 2" (IBM): http://www.ibm.com/developerworks/library/j-dyn0603/