Reflection und Annotationen

Reflection-API

Reflection *

Folgende Nachricht wurde in der JDC Tech Tips No. 5 versendet. Lies den Text und implementiere das Beispielprogramm. Teste es an der Klasse java.math.BigDecimal. Wofür kann man die Technik verwenden? Schreibe ein Programm, welches zu einer geladenen Klasse eine Klassenbeschreibung liefert, wie sie im Quellcode vorliegen könnte. Zu der Beschreibung gehören also Konstruktor, Variablen und Methoden.

Komponenten und Klassen *

Eine Firma möchte Komponenten implementieren und auch anderen Anbietern die Möglichkeit geben, Komponenten zu entwickeln. Da das Einfügen neuer Komponenten möglichst einfach sein soll, sollen sie in ein Verzeichnis gestellt werden. Wird die Software neu gestartet, so soll sie automatisch die neuen Komponenten erkennen und einbinden.

Klasse Class **

Möchte man von einer gegebenen Klasse die Vererbungshierarchie auflisten, so ist dies kein großes Problem. (Wieso?) Es gibt aber auch Situationen im Leben eines Programmierers, in denen er alle direkten erbenden Klassen erfahren möchte. Wo liegen aber dort die Schwierigkeiten?

Allerdings lassen sich in einem absoluten Sonderfall Unterklassen herausfinden. Warum funktioniert für welchen Spezialfall das folgende Programmstück:

Class<?> superC = Point2D.class;
Class[] refs = superC.getClasses();

for ( int i = 0; i < refs.length; i++ )
if ( superC != refs[i] && superC.isAssignableFrom( refs[i] ) )
System.out.println( refs[i] + " is subclass of " + superC );

Teste das Programmsegment.

Implementierung *

Wir wollen als konkretes Beispiel einen Taschenrechner einsetzen, der um mathematische Funktionen erweitert werden soll. Definiere eine Schnittstelle für das Problem. Das kann etwa so aussehen:

interface MathOp
{
  String getName();
  double op( double d1, double d2 );
}

Dann kann eine konkrete implementierende Klasse, die eine Funktion implementiert, Folgendes schreiben:

class Sin implements MathOp
{
  String getName()
  {
    return "sin";
  }
  double op( double d1, double d2 )
  {
    return Math.sin( d1 );
  }
}

Schreibe eine Testklasse, die die mathematische Funktion überprüft. Das kann etwas so aussehen:

public static void main( String args[] )
{
  Sin sin = new Sin();
  // Parameter aufbauen
  System.out.println( sin.op( /* Parameter einsetzen */  ) );
}

Kopiere die eigenen Klassen in die Freigabe TNProjekte auf dem Referenten-PC.
Kopiere anschließend alle mathematischen Klassen in das eigene Verzeichnis.

Die java.io.File-Klasse *

Man kann mit der Methode list() von einem java.io.File eine Auflistung aller Dateien im Verzeichnis erhalten.

Klassen dynamisch laden *

Man kann Klassen mit forName() nachladen, wenn man den Klassennamen kennt. Mit newInstance() kann man dann ein Exemplar der Klasse erzeugen. Ein Beispiel:

Class clazz = Class.forName("java.util.Date");
Object o = clazz.newInstance();

Lade alle mathematischen Klassen im Verzeichnis und erzeuge ein Objekt von ihnen mit Hilfe der newInstance()-Methode. Mit toString() kann man erkennen, ob alles gut ging. Fange die entsprechenden Ausnahmen ab.

Übergebe dazu alle gefundenen Klassen von list() der Methode klasseLaden(), die das Objekt vom Typ MathOp zurückliefert.