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
- API de Reflexió: Java proporciona un conjunt de classes i mètodes dins del paquet
java.lang.reflect
per treballar amb la reflexió. - Classe
Class
: La classeClass
és el punt d'entrada per a la reflexió. Representa una classe o interfície en temps d'execució. - Mètodes de Reflexió: Inclouen mètodes per obtenir informació sobre constructors, mètodes, camps i modificadors d'una classe.
- 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
- ClassNotFoundException: Assegura't que el nom de la classe és correcte i que la classe està en el classpath.
- NoSuchMethodException: Verifica que el mètode existeix i que els tipus de paràmetres són correctes.
- IllegalAccessException: Utilitza
setAccessible(true)
per accedir a camps o mètodes privats. - 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
- Introducció a Java
- Configuració de l'Entorn de Desenvolupament
- Sintaxi i Estructura Bàsica
- Variables i Tipus de Dades
- Operadors
Mòdul 2: Flux de Control
Mòdul 3: Programació Orientada a Objectes
- Introducció a la POO
- Classes i Objectes
- Mètodes
- Constructors
- Herència
- Polimorfisme
- Encapsulació
- Abstracció
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
- Lectura de Fitxers
- Escriptura de Fitxers
- Fluxos de Fitxers
- BufferedReader i BufferedWriter
- Serialització
Mòdul 8: Multithreading i Concurrència
- Introducció al Multithreading
- Creació de Fils
- Cicle de Vida dels Fils
- Sincronització
- Utilitats de Concurrència
Mòdul 9: Xarxes
- Introducció a les Xarxes
- Sockets
- ServerSocket
- DatagramSocket i DatagramPacket
- URL i HttpURLConnection