La reflexión en Java es una poderosa característica que permite a los programas inspeccionar y manipular las propiedades de los objetos en tiempo de ejecución. Esto incluye la capacidad de analizar clases, interfaces, campos y métodos, así como instanciar objetos, invocar métodos y acceder a campos. La reflexión es particularmente útil en situaciones donde el comportamiento del programa debe adaptarse dinámicamente a las clases que no se conocen en tiempo de compilación.

Conceptos Clave

  1. Clase Class: Representa las clases y las interfaces en una aplicación Java.
  2. Métodos de la Clase Class: Métodos como getName(), getMethods(), getFields(), etc., que permiten obtener información sobre la clase.
  3. Instanciación Dinámica: Crear instancias de clases en tiempo de ejecución usando newInstance().
  4. Acceso a Campos y Métodos: Usar las clases Field, Method y Constructor para acceder y manipular campos y métodos de una clase.

Ejemplo Práctico

Inspección de una Clase

Vamos a inspeccionar una clase llamada Persona para obtener información sobre sus métodos y campos.

import java.lang.reflect.*;

class Persona {
    private String nombre;
    private int edad;

    public Persona() {}

    public Persona(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public int getEdad() {
        return edad;
    }

    public void setEdad(int edad) {
        this.edad = edad;
    }
}

public class ReflexionDemo {
    public static void main(String[] args) {
        try {
            // Obtener la clase Persona
            Class<?> clase = Class.forName("Persona");

            // Obtener el nombre de la clase
            System.out.println("Nombre de la clase: " + clase.getName());

            // Obtener los métodos de la clase
            Method[] metodos = clase.getDeclaredMethods();
            System.out.println("Métodos de la clase:");
            for (Method metodo : metodos) {
                System.out.println(metodo.getName());
            }

            // Obtener los campos de la clase
            Field[] campos = clase.getDeclaredFields();
            System.out.println("Campos de la clase:");
            for (Field campo : campos) {
                System.out.println(campo.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Explicación del Código

  1. Obtener la Clase: Usamos Class.forName("Persona") para obtener la clase Persona.
  2. Nombre de la Clase: clase.getName() devuelve el nombre completo de la clase.
  3. Métodos de la Clase: clase.getDeclaredMethods() devuelve un array de objetos Method que representan todos los métodos declarados en la clase.
  4. Campos de la Clase: clase.getDeclaredFields() devuelve un array de objetos Field que representan todos los campos declarados en la clase.

Instanciación Dinámica

Podemos crear una instancia de la clase Persona en tiempo de ejecución usando reflexión.

public class ReflexionDemo {
    public static void main(String[] args) {
        try {
            // Obtener la clase Persona
            Class<?> clase = Class.forName("Persona");

            // Crear una instancia de Persona
            Object persona = clase.getDeclaredConstructor().newInstance();

            // Obtener el método setNombre y setEdad
            Method setNombre = clase.getMethod("setNombre", String.class);
            Method setEdad = clase.getMethod("setEdad", int.class);

            // Invocar los métodos en la instancia de Persona
            setNombre.invoke(persona, "Juan");
            setEdad.invoke(persona, 30);

            // Obtener el método getNombre y getEdad
            Method getNombre = clase.getMethod("getNombre");
            Method getEdad = clase.getMethod("getEdad");

            // Invocar los métodos y obtener los valores
            String nombre = (String) getNombre.invoke(persona);
            int edad = (int) getEdad.invoke(persona);

            System.out.println("Nombre: " + nombre);
            System.out.println("Edad: " + edad);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Explicación del Código

  1. Crear Instancia: clase.getDeclaredConstructor().newInstance() crea una nueva instancia de la clase Persona.
  2. Obtener Métodos: clase.getMethod("setNombre", String.class) obtiene el método setNombre que toma un String como parámetro.
  3. Invocar Métodos: setNombre.invoke(persona, "Juan") invoca el método setNombre en la instancia persona con el argumento "Juan".
  4. Obtener Valores: getNombre.invoke(persona) invoca el método getNombre y devuelve el valor del nombre.

Ejercicio Práctico

Ejercicio

Crea una clase llamada Producto con los siguientes campos y métodos:

  • Campos: nombre (String), precio (double)
  • Métodos: getNombre(), setNombre(String nombre), getPrecio(), setPrecio(double precio)

Usa reflexión para:

  1. Crear una instancia de Producto.
  2. Establecer el nombre y el precio del producto.
  3. Obtener y mostrar el nombre y el precio del producto.

Solución

import java.lang.reflect.*;

class Producto {
    private String nombre;
    private double precio;

    public Producto() {}

    public Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public double getPrecio() {
        return precio;
    }

    public void setPrecio(double precio) {
        this.precio = precio;
    }
}

public class ReflexionProducto {
    public static void main(String[] args) {
        try {
            // Obtener la clase Producto
            Class<?> clase = Class.forName("Producto");

            // Crear una instancia de Producto
            Object producto = clase.getDeclaredConstructor().newInstance();

            // Obtener los métodos setNombre y setPrecio
            Method setNombre = clase.getMethod("setNombre", String.class);
            Method setPrecio = clase.getMethod("setPrecio", double.class);

            // Invocar los métodos en la instancia de Producto
            setNombre.invoke(producto, "Laptop");
            setPrecio.invoke(producto, 999.99);

            // Obtener los métodos getNombre y getPrecio
            Method getNombre = clase.getMethod("getNombre");
            Method getPrecio = clase.getMethod("getPrecio");

            // Invocar los métodos y obtener los valores
            String nombre = (String) getNombre.invoke(producto);
            double precio = (double) getPrecio.invoke(producto);

            System.out.println("Nombre: " + nombre);
            System.out.println("Precio: " + precio);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Conclusión

La reflexión en Java es una herramienta poderosa que permite a los desarrolladores inspeccionar y manipular clases, métodos y campos en tiempo de ejecución. Aunque es muy útil, debe usarse con cuidado debido a su impacto en el rendimiento y la seguridad. Con la práctica, la reflexión puede ser una adición valiosa a tu conjunto de habilidades de programación en Java.

Curso de Programación en Java

Módulo 1: Introducción a Java

Módulo 2: Flujo de Control

Módulo 3: Programación Orientada a Objetos

Módulo 4: Programación Orientada a Objetos Avanzada

Módulo 5: Estructuras de Datos y Colecciones

Módulo 6: Manejo de Excepciones

Módulo 7: Entrada/Salida de Archivos

Módulo 8: Multihilo y Concurrencia

Módulo 9: Redes

Módulo 10: Temas Avanzados

Módulo 11: Frameworks y Librerías de Java

Módulo 12: Construcción de Aplicaciones del Mundo Real

© Copyright 2024. Todos los derechos reservados