La reflexió és una característica poderosa de Java que permet a un programa inspeccionar i manipular les seves pròpies estructures internes en temps d'execució. Això inclou la capacitat d'examinar classes, mètodes, camps i constructors, així com invocar mètodes i accedir a camps de manera dinàmica.

Conceptes Clau

  1. API de Reflexió: Java proporciona un conjunt de classes i mètodes dins del paquet java.lang.reflect per treballar amb la reflexió.
  2. Classe Class: La classe Class és el punt d'entrada per a la reflexió. Representa una classe o interfície en temps d'execució.
  3. Mètodes de Reflexió: Inclouen mètodes per obtenir informació sobre constructors, mètodes, camps i modificadors d'una classe.
  4. Invocació Dinàmica: Permet invocar mètodes i accedir a camps de manera dinàmica, és a dir, sense conèixer els noms dels mètodes o camps en temps de compilació.

Exemples Pràctics

Obtenir Informació sobre una Classe

public class Example {
    private String field;

    public Example() {}

    public void method() {}
}

public class ReflectionDemo {
    public static void main(String[] args) {
        try {
            // Obtenir l'objecte Class
            Class<?> clazz = Class.forName("Example");

            // Obtenir el nom de la classe
            System.out.println("Nom de la classe: " + clazz.getName());

            // Obtenir els camps de la classe
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("Camp: " + field.getName());
            }

            // Obtenir els mètodes de la classe
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println("Mètode: " + method.getName());
            }

            // Obtenir els constructors de la classe
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println("Constructor: " + constructor.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Invocar Mètodes Dinàmicament

public class Example {
    public void sayHello(String name) {
        System.out.println("Hola, " + name);
    }
}

public class ReflectionDemo {
    public static void main(String[] args) {
        try {
            // Obtenir l'objecte Class
            Class<?> clazz = Class.forName("Example");

            // Crear una instància de la classe
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // Obtenir el mètode
            Method method = clazz.getDeclaredMethod("sayHello", String.class);

            // Invocar el mètode
            method.invoke(instance, "Món");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Accedir a Camps Privats

public class Example {
    private String secret = "Això és un secret";

    public String getSecret() {
        return secret;
    }
}

public class ReflectionDemo {
    public static void main(String[] args) {
        try {
            // Obtenir l'objecte Class
            Class<?> clazz = Class.forName("Example");

            // Crear una instància de la classe
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // Obtenir el camp privat
            Field field = clazz.getDeclaredField("secret");

            // Fer el camp accessible
            field.setAccessible(true);

            // Obtenir el valor del camp
            String secretValue = (String) field.get(instance);
            System.out.println("Valor del camp secret: " + secretValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Exercicis Pràctics

Exercici 1: Obtenir Informació sobre una Classe

Descripció: Escriu un programa que obtingui i imprimeixi informació sobre una classe especificada per l'usuari, incloent els seus camps, mètodes i constructors.

Solució:

import java.lang.reflect.*;

public class ClassInfo {
    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("Ús: java ClassInfo <nom de la classe>");
            return;
        }

        try {
            Class<?> clazz = Class.forName(args[0]);

            System.out.println("Nom de la classe: " + clazz.getName());

            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("Camp: " + field.getName());
            }

            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println("Mètode: " + method.getName());
            }

            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println("Constructor: " + constructor.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Exercici 2: Invocar un Mètode Dinàmicament

Descripció: Escriu un programa que invoca un mètode especificat per l'usuari en una classe especificada per l'usuari, passant un argument també especificat per l'usuari.

Solució:

import java.lang.reflect.*;

public class DynamicMethodInvocation {
    public static void main(String[] args) {
        if (args.length != 3) {
            System.out.println("Ús: java DynamicMethodInvocation <nom de la classe> <nom del mètode> <argument>");
            return;
        }

        try {
            Class<?> clazz = Class.forName(args[0]);
            Object instance = clazz.getDeclaredConstructor().newInstance();
            Method method = clazz.getDeclaredMethod(args[1], String.class);
            method.invoke(instance, args[2]);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Errors Comuns i Consells

  1. ClassNotFoundException: Assegura't que el nom de la classe és correcte i que la classe està en el classpath.
  2. NoSuchMethodException: Verifica que el mètode existeix i que els tipus de paràmetres són correctes.
  3. IllegalAccessException: Utilitza setAccessible(true) per accedir a camps o mètodes privats.
  4. InvocationTargetException: Aquest error es produeix quan el mètode invocat llança una excepció. Gestiona les excepcions adequadament.

Conclusió

La reflexió és una eina poderosa que permet als desenvolupadors escriure codi més flexible i dinàmic. Tot i això, s'ha d'utilitzar amb precaució, ja que pot afectar el rendiment i la seguretat de l'aplicació. Amb la pràctica i la comprensió adequada, la reflexió pot ser una addició valuosa a l'arsenal de qualsevol programador Java.

Curs de Programació en Java

Mòdul 1: Introducció a Java

Mòdul 2: Flux de Control

Mòdul 3: Programació Orientada a Objectes

Mòdul 4: Programació Orientada a Objectes Avançada

Mòdul 5: Estructures de Dades i Col·leccions

Mòdul 6: Gestió d'Excepcions

Mòdul 7: Entrada/Sortida de Fitxers

Mòdul 8: Multithreading i Concurrència

Mòdul 9: Xarxes

Mòdul 10: Temes Avançats

Mòdul 11: Frameworks i Llibreries de Java

Mòdul 12: Construcció d'Aplicacions del Món Real

© Copyright 2024. Tots els drets reservats