1. Informationen über Felder abrufen
Worin unterscheiden sich getFields() und getDeclaredFields()
In Java hat jede Klasse Felder (fields) – Variablen, die innerhalb der Klasse deklariert sind. Mithilfe von Reflection können wir ihre Namen, Typen, Zugriffsmodifizierer (public/private) ermitteln und zur Laufzeit auf sie zugreifen. Der Haupteinstiegspunkt ist das Objekt Class<?>.
Wichtige Methoden der Klasse Class für die Arbeit mit Feldern:
| Methode | Was wird zurückgegeben |
|---|---|
|
Ein Array aller public-Felder der Klasse, ihrer Oberklassen und Interfaces |
|
Ein Array aller in dieser Klasse deklarierten Felder |
Analogie: getFields() – wie eine Führung nur durch die Schauräume (public), und getDeclaredFields() – auch durch die Technikräume (private, protected, package-private).
Beispiel: Alle Felder der Klasse ausgeben
Angenommen, wir haben eine Klasse:
public class Person {
public String name;
private int age;
protected String email;
}
Wir holen die Informationen über die Felder:
import java.lang.reflect.Field;
Class<?> clazz = Person.class;
// Alle public-Felder (einschließlich geerbter)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
// Alle deklarierten Felder (einschließlich private, nur eigene)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
Ergebnis:
Public fields:
name : String
Declared fields:
name : String
age : int
email : String
Wie ermittelt man die Modifizierer eines Feldes?
Jedes Feld (Field) hat Modifizierer (public/private/protected, static, final usw.). Man kann sie über getModifiers() abrufen und mit Modifier in eine Zeichenkette umwandeln:
import java.lang.reflect.Modifier;
for (Field field : clazz.getDeclaredFields()) {
int mods = field.getModifiers();
System.out.println(field.getName() + " : " + Modifier.toString(mods));
}
2. Informationen über Methoden abrufen
Methoden getMethods() und getDeclaredMethods()
Methoden sind die Aktionen, die ein Objekt ausführen kann. Mit Reflection kann man herausfinden, welche Methoden eine Klasse hat, ihre Parameter, Rückgabetypen, Modifizierer und Annotationen.
| Methode | Was wird zurückgegeben |
|---|---|
|
Alle public-Methoden der Klasse und ihrer Oberklassen (einschließlich Object) |
|
Alle in dieser Klasse deklarierten Methoden (einschließlich private) |
Beispiel: Alle Methoden der Klasse ausgeben
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());
}
Ergebnis (für Person):
Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait
Declared methods:
(nichts, wenn in Person keine eigenen Methoden deklariert sind)
Fügen wir eine Methode zu Person hinzu:
public class Person {
public String name;
private int age;
protected String email;
public void sayHello() {
System.out.println("Hi!");
}
}
Jetzt zeigt getDeclaredMethods() auch diese an.
Wie ermittelt man Parameter und Rückgabetyp einer Methode?
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(");");
}
Ausgabe:
public void sayHello();
3. Informationen über Konstruktoren abrufen
Konstruktoren sind spezielle Methoden, mit denen Objekte erstellt werden.
| Methode | Was wird zurückgegeben |
|---|---|
|
Alle public-Konstruktoren |
|
Alle in der Klasse deklarierten Konstruktoren |
Beispiel: Alle Konstruktoren der Klasse ausgeben
import java.lang.reflect.Constructor;
System.out.println("Constructors:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(clazz.getSimpleName() + "(");
Class<?>[] params = constructor.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(");");
}
Wenn in der Klasse nur der Standardkonstruktor deklariert ist, wird auch dieser ausgegeben.
4. Annotationen: Wie findet man heraus, womit Klasse, Methode oder Feld annotiert sind
Annotationen sind spezielle Markierungen, die man an Klassen, Methoden, Feldern und Parametern anbringen kann. Mit Reflection kann man ermitteln, welche Annotationen ein Element hat.
Annotationen abrufen
- Für die Klasse: clazz.getAnnotations()
- Für die Methode: method.getAnnotations()
- Für das Feld: field.getAnnotations()
Beispiel: Prüfen, ob die Annotation @Deprecated vorhanden ist
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println(method.getName() + " is @Deprecated");
}
}
Beispiel: Alle Annotationen der Klasse ausgeben
for (var annotation : clazz.getAnnotations()) {
System.out.println(annotation);
}
5. Praxis: Mini-Programm zur Analyse der Klassenstruktur
Fassen wir alles zusammen und schreiben ein kleines Hilfsprogramm, das anhand des Klassennamens seine Struktur ausgibt: Felder, Methoden, Konstruktoren und Annotationen.
Codebeispiel: 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("Geben Sie den vollqualifizierten Klassennamen ein (z. B. java.util.ArrayList): ");
String className = scanner.nextLine();
Class<?> clazz = Class.forName(className);
System.out.println("\n== Klasse: " + clazz.getName() + " ==");
// Annotationen der Klasse
System.out.println("Annotationen:");
for (Annotation annotation : clazz.getAnnotations()) {
System.out.println(" " + annotation);
}
// Felder
System.out.println("\nFelder:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" " + Modifier.toString(field.getModifiers())
+ " " + field.getType().getSimpleName()
+ " " + field.getName());
}
// Methoden
System.out.println("\nMethoden:");
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(");");
}
// Konstruktoren
System.out.println("\nKonstruktoren:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(" " + Modifier.toString(constructor.getModifiers())
+ " " + clazz.getSimpleName() + "(");
Class<?>[] params = constructor.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(");");
}
}
}
Wie funktioniert das?
- Der Benutzer gibt den vollqualifizierten Klassennamen ein (z. B. "java.util.ArrayList" oder eine eigene Klasse).
- Das Programm lädt die Klasse dynamisch und gibt ihre Annotationen, Felder, Methoden und Konstruktoren aus.
- Probieren Sie es mit Standardklassen der JDK – Sie werden sehen, wie viel Interessantes darin steckt!
6. Nützliche Details und Visualisierung
Schaubild: Was man über eine Klasse per Reflection herausfinden kann
graph TD
A[Class<?>] --> B["getFields/getDeclaredFields"]
A --> C[getMethods/getDeclaredMethods]
A --> D[getConstructors/getDeclaredConstructors]
A --> E[getAnnotations]
B --> F[Field: Typ, Name, Modifizierer]
C --> G[Method: Rückgabetyp, Parameter]
D --> H[Constructor: Parameter]
E --> I["Annotation[]"]
Tabelle: Wo finde ich welche Information
| Was wollen wir wissen | Wie per Reflection abrufen |
|---|---|
| Alle public-Felder | |
| Alle deklarierten Felder | |
| Alle public-Methoden | |
| Alle deklarierten Methoden | |
| Alle public-Konstruktoren | |
| Alle deklarierten Konstruktoren | |
| Annotationen der Klasse | |
| Annotationen von Methode/Feld | |
| Modifizierer | |
7. Typische Fehler beim Arbeiten mit Reflection
Fehler Nr. 1: getFields() und getDeclaredFields() werden verwechselt.
Wenn Sie private-Felder suchen, verwenden Sie getDeclaredFields() und nicht getFields(). Ersteres liefert alle in der Klasse deklarierten Felder, Letzteres nur public (und geerbte!).
Fehler Nr. 2: Checked Exceptions werden nicht behandelt.
Viele Reflection-APIs werfen Ausnahmen (z. B. ClassNotFoundException oder SecurityException). Vergessen Sie nicht, sie zu behandeln oder in der Methodensignatur zu deklarieren.
Fehler Nr. 3: Zugriffsmodifizierer werden nicht berücksichtigt.
Zugriff auf private-Felder und -Methoden ist nur nach Aufruf von setAccessible(true) möglich, sonst gibt es eine IllegalAccessException. Beispiel:
Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // Zugriff auf das private Feld erlauben
int value = (int) field.get(person);
Fehler Nr. 4: Es werden nur eigene Methoden/Felder erwartet.
getMethods() und getFields() liefern public-Member nicht nur der aktuellen Klasse, sondern auch aller Oberklassen, einschließlich Object. Das kann überraschen, wenn Sie nur das sehen wollen, was Sie selbst geschrieben haben.
Fehler Nr. 5: Vorhandensein von Annotationen wird falsch geprüft.
Verwenden Sie isAnnotationPresent() zur Prüfung auf eine konkrete Annotation, statt ohne Not den Array der Annotationen manuell zu durchlaufen.
GO TO FULL VERSION