Was ist Reflection?
Reflection ist eine API, die es ermöglicht, über ein Objekt vom Typ Class, das im Heap-Bereich geladen wurde, eine Instanz der gewünschten Klasse zu erstellen und auf die Felder und Methoden der Instanz zuzugreifen, unabhängig von den Zugriffsspezifizierern.
Dabei bezieht sich "geladene Klasse" auf den Zustand, nachdem der Classloader der JVM das Laden der Klassendatei abgeschlossen hat und ein Objekt vom Typ Classerzeugt und im Heap-Bereich des Speichers abgelegt hat, welches die Informationen der Klasse enthält. Beachten Sie, dass dies sich von Objekten unterscheidet, die mit dem Schlüsselwort new erstellt werden. Wenn Sie das Objekt vom Typ Class nicht verstehen, sollten Sie die JDK-Dokumentation zu java.lang.class konsultieren.
Verwendungsweise
Bevor Reflection verwendet werden kann, muss das Objekt vom Typ Class, das im Heap-Bereich geladen wurde, abgerufen werden. Es gibt drei Möglichkeiten, dies zu tun.
- Abrufen über Klasse.class
- Abrufen über Instanz.getClass()
- Abrufen über Class.forName("Klassenname")
Man kann feststellen, dass die mit den drei Methoden abgerufenen Instanzen vom Typ Class alle identisch sind. Unabhängig von der verwendeten Methode ist der Hash-Wert gleich, sodass sie je nach Situation verwendet werden können.
Nun können wir mithilfe des abgerufenen Class-Typs eine Instanz der entsprechenden Klasse erstellen und auf die Felder und Methoden der Instanz zugreifen, unabhängig von den Zugriffsspezifizierern. Lassen Sie uns zunächst eine Instanz der entsprechenden Klasse erstellen.
Mit getConstructor() kann der Konstruktor abgerufen und mit newInstance() eine Member-Instanz dynamisch erstellt werden.
Schließlich wollen wir auf die Felder und Methoden der Instanz zugreifen, unabhängig von den Zugriffsspezifizierern.
Mit getDeclaredFileds() können alle Instanzvariablen der Klasse abgerufen werden. Mit get() kann der Feldwert zurückgegeben und mit set() der Feldwert geändert werden. Zu beachten ist, dass bei Zugriff auf ein Feld mit dem Zugriffsspezifizierer private der Parameter von setAccessible() auf true gesetzt werden muss.
Auch Methoden können mit getDeclaredMethod() abgerufen werden. Dabei müssen der Name der Methode und der Typ der Parameter als Argumente übergeben werden. Auch hier muss der Parameter von setAccessible() auf true gesetzt werden, wenn auf eine Methode mit dem Zugriffsspezifizierer private zugegriffen werden soll. Schließlich kann die mit der Reflection-API abgerufene Methode mit der Methode invoke() aufgerufen werden.
Vor- und Nachteile
- Vorteile
- Reflection bietet die Flexibilität, zur Laufzeit Instanzen von Klassen zu erstellen und unabhängig von den Zugriffsspezifizierern auf Felder und Methoden zuzugreifen, um die erforderlichen Aufgaben auszuführen.
- Nachteile
- Verletzung der Kapselung.
- Da die Instanzen zur Laufzeit erstellt werden, kann der Typ nicht zur Kompilierzeit überprüft werden.
- Da die Instanzen zur Laufzeit erstellt werden, ist es schwierig, den genauen Ablauf des Programms zu verstehen.
- Der Zugriff auf Felder und Methoden über Reflection ist im Allgemeinen langsamer als der direkte Zugriff. (Dies gilt nicht für alle Situationen.)
Gründe für die Verwendung
Mithilfe der Reflection-API kann während der Laufzeit auf Klasseninformationen zugegriffen und die Klassen nach Bedarf manipuliert werden. Sogar Felder und Methoden, die mit dem Zugriffsspezifizierer private deklariert wurden, können manipuliert werden. Da dies die Kapselung verletzt, die ein wichtiger Aspekt des objektorientierten Designs ist, mag es so aussehen, als ob diese Technik vermieden werden sollte.
Bei kleinen Konsolenanwendungen kann der Entwickler zur Kompilierzeit alle Objekte und Abhängigkeiten identifizieren, die im Programm verwendet werden. Bei größeren Entwicklungsprojekten wie Frameworks ist es jedoch schwierig, die vielen Objekte und Abhängigkeiten zu identifizieren. In solchen Fällen kann Reflection verwendet werden, um dynamisch Klassen zu erstellen und Abhängigkeiten herzustellen.
Beispielsweise kann man bei der Bean Factory von Spring sehen, dass die Bean Factory automatisch die Klasse erzeugt und verwaltet, wenn man nur die Annotationen @Controller, @Service oder @Repository an die Klasse anhängt. Der Entwickler hat der Bean Factory diese Klasse nie mitgeteilt. Dies ist durch Reflection möglich. Während der Laufzeit werden Klassen mit den entsprechenden Annotationen durchsucht. Wenn eine solche Klasse gefunden wird, wird mithilfe von Reflection eine Instanz dieser Klasse erstellt, die erforderlichen Felder injiziert und in der Bean Factory gespeichert.
Wie bereits erwähnt, sollte Reflection aufgrund der Verletzung der Kapselung nur in notwendigen Situationen verwendet werden.
Kommentare0