Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 45 - Reflection |
Nachdem wir uns in den vorangegangenen Abschnitten die beiden Reflection-Aspekte Instanzierung und Methodenaufruf angesehen haben, wollen wir uns nun mit dem Zugriff auf Membervariablen (also auf die »Felder« eines Objekts) mit Hilfe von Reflection beschäftigen. Prinzipiell gibt es keine großen Unterschiede gegenüber dem Zugriff auf eine Methode oder einen Konstruktor:
Der erste Schritt erfolgt wie gewohnt durch Aufruf von getClass oder die .class-Notation. Die im zweiten Schritt benötigten Bearbeitungsobjekte sind vom Typ Field, sie können auf dem Klassenobjekt durch Aufruf einer der folgenden Methoden beschafft werden:
Field getField(String name) Field[] getFields() Field getDeclaredField(String name) Field[] getDeclaredFields() |
java.lang.Class |
Mit getField wird die Membervariable mit dem angegebenen Namen beschafft und getFields liefert ein Array mit Field-Objekten zu allen öffentlichen Membervariablen. Die beiden Methoden getDeclaredField und getDeclaredFields liefern darüber hinaus auch nichtöffentliche Membervariablen.
Die Klasse Field besitzt Methoden zum Zugriff auf die Membervariable:
Class<?> getType() Object get(Object obj) void set(Object obj, Object value) |
java.lang.reflect.Field |
Mit getType kann der Typ der Membervariable bestimmt werden. Das zurückgegebene Klassenobjekt beschreibt ihn in derselben Weise wie beispielsweise das Parameterobjekt von getMethod. Mit get kann auf den Wert zugegriffen werden, den die Membervariable in dem als Argument übergebenen Objekt hat. Handelt es sich um einen primitiven Typ, wird dieser automatisch in die passende Wrapper-Klasse verpackt und als Objekt zurückgegeben. Referenztypen werden unverändert zurückgegeben. Mit Hilfe der Methode set kann der Wert einer Membervariable verändert werden. Das erste Argument repräsentiert das zu veränderende Objekt, das zweite den neuen Wert der Membervariable. Soll ein primitiver Typ verändert werden, muss er vor der Übergabe in die passende Wrapper-Klasse verpackt werden.
Neben den generischen get- und set-Methoden gibt es diese auch in typisierter Form. So dient beispielsweise getInt dazu, ein int-Feld abzufragen, mit getDouble kann auf ein double zugegriffen werden usw. Das Gegenstück dazu sind die Methoden setInt, setDouble usw., mit denen die Membervariablen typisiert verändert werden können. |
|
Wir wollen als Beispiel eine Klasse PrintableObject erstellen, die direkt aus Object abgeleitet ist und die Methode toString überlagert. Im Gegensatz zur Implementierung von Object soll unsere Variante von toString in der Lage sein, die Namen und Inhalte aller Membervariablen des zugehörigen Objekts auszugeben:
001 /* PrintableObject.java */ 002 003 import java.lang.reflect.*; 004 005 public class PrintableObject 006 { 007 public String toString() 008 { 009 StringBuffer sb = new StringBuffer(200); 010 Class<?> clazz = getClass(); 011 while (clazz != null) { 012 Field[] fields = clazz.getDeclaredFields(); 013 for (int i = 0; i < fields.length; ++i) { 014 sb.append(fields[i].getName() + " = "); 015 try { 016 Object obj = fields[i].get(this); 017 if (obj.getClass().isArray()) { 018 Object[] ar = (Object[])obj; 019 for (int j = 0; j < ar.length; ++j) { 020 sb.append(ar[j].toString() + " "); 021 } 022 sb.append("\n"); 023 } else { 024 sb.append(obj.toString() + "\n"); 025 } 026 } catch (IllegalAccessException e) { 027 sb.append(e.toString() + "\n"); 028 } 029 } 030 clazz = clazz.getSuperclass(); 031 } 032 return sb.toString(); 033 } 034 035 public static void main(String[] args) 036 { 037 JavaProgrammer jim = new JavaProgrammer(); 038 jim.name = "Jim Miller"; 039 jim.department = "Operating Systems"; 040 jim.age = 32; 041 String[] langs = {"C", "Pascal", "PERL", "Java"}; 042 jim.languages = langs; 043 jim.linesofcode = 55000; 044 jim.jdk12 = true; 045 jim.swing = false; 046 System.out.println(jim); 047 } 048 } 049 050 class Employee 051 extends PrintableObject 052 { 053 public String name; 054 public String department; 055 public int age; 056 } 057 058 class Programmer 059 extends Employee 060 { 061 public String[] languages; 062 public int linesofcode; 063 } 064 065 class JavaProgrammer 066 extends Programmer 067 { 068 public boolean jdk12; 069 public boolean swing; 070 } |
PrintableObject.java |
toString besorgt zunächst ein Klassenobjekt zum aktuellen Objekt. Mit getDeclaredFields wird dann eine Liste aller Felder (nicht nur der öffentlichen) dieser Klasse besorgt und jeweils mit getName sein Name und mit get sein Wert ausgegeben. Wir machen uns dabei die Fähigkeit zunutze, dass alle Objekte (auch die Wrapper-Klassen der primitiven Typen) eine Methode toString haben, die ihren Wert als String liefert. Ist die Membervariable ein Array, durchläuft das Programm dessen Elemente und gibt sie einzeln aus.
Da eine Klasse Membervariablen aus ihren Vaterklassen erbt, ist es notwendig, die Vererbungshierarchie von unten nach oben zu durchlaufen, denn getDeclaredFields liefert nur die Membervariablen der aktuellen Klasse. Der Aufruf von getSuperClass am Ende der Schleife liefert zur aktuellen Klasse die Vaterklasse. Ist der Rückgabewert null, ist das Ende der Vererbungshierarchie erreicht (clazz repräsentiert dann die Klasse Object) und die Schleife wird beendet.
Die Klassen Employee, Programmer
und JavaProgrammer zeigen beispielhaft
die Anwendung von PrintableObject.
Employee ist aus PrintableObject
abgeleitet und erbt die modifizierte Methode toString.
Programmer ist aus Employee
abgeleitet und JavaProgrammer
aus Programmer. Das Hauptprogramm
erzeugt ein Objekt des Typs JavaProgrammer
und weist seinen eigenen und den geerbten Membervariablen Werte zu,
die durch den anschließenden Aufruf von toString
auf dem Bildschirm ausgegeben werden. Die Ausgabe des Programms ist:
jdk12 = true
swing = false
languages = C Pascal PERL Java
linesofcode = 55000
name = Jim Miller
department = Operating Systems
age = 32
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0 |
<< | < | > | >> | API | © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de |