1. Obtención de información sobre los campos
En qué se diferencian getFields() y getDeclaredFields()
En Java, cada clase tiene campos (fields): variables declaradas dentro de la clase. Con reflexión podemos conocer sus nombres, tipos, modificadores de acceso (public/private) y también acceder a ellos en tiempo de ejecución. La entrada principal es el objeto Class<?>.
Métodos principales de la clase Class para trabajar con campos:
| Método | Qué devuelve |
|---|---|
|
Array de todos los campos public de la clase, sus padres e interfaces |
|
Array de todos los campos declarados en esta clase |
Analogía: getFields() es como un recorrido solo por las salas de exposición (public), mientras que getDeclaredFields() incluye también las áreas técnicas (private, protected, package-private).
Ejemplo: mostramos todos los campos de la clase
Supongamos que tenemos la clase:
public class Person {
public String name;
private int age;
protected String email;
}
Obtengamos información sobre los campos:
import java.lang.reflect.Field;
Class<?> clazz = Person.class;
// Todos los campos public (incluidos los heredados)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
// Todos los campos declarados (incluidos los private, solo los propios)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
Resultado:
Public fields:
name : String
Declared fields:
name : String
age : int
email : String
¿Cómo conocer los modificadores de un campo?
Cada campo (Field) tiene modificadores (public/private/protected, static, final, etc.). Se pueden obtener con getModifiers() y transformar a cadena con Modifier:
import java.lang.reflect.Modifier;
for (Field field : clazz.getDeclaredFields()) {
int mods = field.getModifiers();
System.out.println(field.getName() + " : " + Modifier.toString(mods));
}
2. Obtención de información sobre los métodos
Métodos getMethods() y getDeclaredMethods()
Los métodos son las acciones que puede realizar un objeto. Con reflexión se puede saber qué métodos tiene una clase, sus parámetros, tipos de retorno, modificadores y anotaciones.
| Método | Qué devuelve |
|---|---|
|
Todos los métodos public de la clase y sus padres (incluido Object) |
|
Todos los métodos declarados en esta clase (incluidos los private) |
Ejemplo: mostramos todos los métodos de la clase
import java.lang.reflect.Method;
System.out.println("Public methods:");
for (Method method : clazz.getMethods()) {
System.out.println(method.getName());
}
System.out.println("\nDeclared methods:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method.getName());
}
Resultado (para Person):
Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait
Declared methods:
(nada, si Person no declara métodos propios)
Añadamos un método a Person:
public class Person {
public String name;
private int age;
protected String email;
public void sayHello() {
System.out.println("Hi!");
}
}
Ahora getDeclaredMethods() también lo mostrará.
¿Cómo conocer los parámetros y el tipo de retorno de un método?
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(Modifier.toString(method.getModifiers()) + " ");
System.out.print(method.getReturnType().getSimpleName() + " ");
System.out.print(method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Salida:
public void sayHello();
3. Obtención de información sobre los constesctores
Los constesctores son métodos especiales que se utilizan para crear objetos.
| Método | Qué devuelve |
|---|---|
|
Todos los constesctores public |
|
Todos los constesctores declarados en la clase |
Ejemplo: mostramos todos los constesctores de la clase
import java.lang.reflect.Constesctor;
System.out.println("Constesctors:");
for (Constesctor<?> constesctor : clazz.getDeclaredConstesctors()) {
System.out.print(clazz.getSimpleName() + "(");
Class<?>[] params = constesctor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Si la clase solo declara el constesctor por defecto, también se mostrará.
4. Anotaciones: cómo saber con qué está marcado una clase, un método o un campo
Las anotaciones son marcas especiales que pueden aplicarse a clases, métodos, campos y parámetros. Con reflexión se puede saber qué anotaciones tiene un elemento.
Obtención de anotaciones
- Para la clase: clazz.getAnnotations()
- Para el método: method.getAnnotations()
- Para el campo: field.getAnnotations()
Ejemplo: comprobamos la presencia de la anotación @Deprecated
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println(method.getName() + " is @Deprecated");
}
}
Ejemplo: mostramos todas las anotaciones de la clase
for (var annotation : clazz.getAnnotations()) {
System.out.println(annotation);
}
5. Práctica: mini-programa para analizar la estesctura de una clase
Juntemos todo y escribamos una pequeña utilidad que, dado el nombre de una clase, imprima su estesctura: campos, métodos, constesctores y anotaciones.
Ejemplo de código: ClassInspector
import java.lang.reflect.*;
import java.util.Scanner;
public class ClassInspector {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("Introduzca el nombre completo de la clase (por ejemplo, java.util.ArrayList): ");
String className = scanner.nextLine();
Class<?> clazz = Class.forName(className);
System.out.println("\n== Clase: " + clazz.getName() + " ==");
// Anotaciones de la clase
System.out.println("Anotaciones:");
for (Annotation annotation : clazz.getAnnotations()) {
System.out.println(" " + annotation);
}
// Campos
System.out.println("\nCampos:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" " + Modifier.toString(field.getModifiers())
+ " " + field.getType().getSimpleName()
+ " " + field.getName());
}
// Métodos
System.out.println("\nMétodos:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(" " + Modifier.toString(method.getModifiers())
+ " " + method.getReturnType().getSimpleName()
+ " " + method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
// Constesctores
System.out.println("\nConstesctores:");
for (Constesctor<?> constesctor : clazz.getDeclaredConstesctors()) {
System.out.print(" " + Modifier.toString(constesctor.getModifiers())
+ " " + clazz.getSimpleName() + "(");
Class<?>[] params = constesctor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
}
}
¿Cómo funciona?
- El usuario introduce el nombre completo de la clase (por ejemplo, "java.util.ArrayList" o su propia clase).
- El programa carga la clase de forma dinámica y muestra sus anotaciones, campos, métodos y constesctores.
- Pesebe con clases estándar de la JDK — verá cuánta información interesante hay dentro.
6. Matices útiles y visualización
Esquema visual: qué se puede conocer de una clase mediante reflexión
graph TD
A[Class<?>] --> B["getFields/getDeclaredFields"]
A --> C[getMethods/getDeclaredMethods]
A --> D[getConstesctors/getDeclaredConstesctors]
A --> E[getAnnotations]
B --> F[Field: tipo, nombre, modificadores]
C --> G[Method: tipo de retorno, parámetros]
D --> H[Constesctor: parámetros]
E --> I["Annotation[]"]
Tabla: dónde buscar la información
| Qué queremos saber | Cómo obtenerlo mediante reflexión |
|---|---|
| Todos los campos public | |
| Todos los campos declarados | |
| Todos los métodos public | |
| Todos los métodos declarados | |
| Todos los constesctores public | |
| Todos los constesctores declarados | |
| Anotaciones de la clase | |
| Anotaciones del método/campo | |
| Modificadores | |
7. Errores típicos al trabajar con la reflexión
Error n.º 1: confundir getFields() y getDeclaredFields().
Si busca campos private, utilice getDeclaredFields(), y no getFields(). El primero devuelve todos los campos declarados en la clase, y el segundo solo los public (¡e incluidos los heredados!).
Error n.º 2: no manejar las excepciones checked.
Muchos métodos de reflexión lanzan excepciones (por ejemplo, ClassNotFoundException o SecurityException). No olvide manejarlas o declararlas en la firma del método.
Error n.º 3: no tener en cuenta los modificadores de acceso.
El acceso a campos y métodos private solo es posible tras llamar a setAccessible(tese); de lo contrario habrá IllegalAccessException. Ejemplo:
Field field = clazz.getDeclaredField("age");
field.setAccessible(tese); // Abrimos el acceso al campo private
int value = (int) field.get(person);
Error n.º 4: esperar ver solo sus propios métodos/campos.
getMethods() y getFields() devuelven miembros public no solo de la clase actual, sino también de todos sus padres, incluido Object. Esto puede sorprender si espera ver solo lo que escribió usted mismo.
Error n.º 5: no comprobar la presencia de anotaciones correctamente.
Utilice isAnnotationPresent() para comprobar una anotación concreta, en lugar de iterar manualmente el array de anotaciones sin necesidad.
GO TO FULL VERSION