Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage
 <<    <     >    >>   API  Kapitel 45 - Reflection

45.4 Zugriff auf Membervariablen



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:

  1. Zunächst wird ein Klassenobjekt für das zu bearbeitende Objekt beschafft.
  2. Dann wird eine Methode aufgerufen, um ein Bearbeitungsobjekt für eine ganz bestimmte oder eine Liste aller Membervariablen zu beschaffen.
  3. Das Bearbeitungsobjekt wird verwendet, um die Membervariable zu lesen, zu verändern oder andere Eigenschaften abzufragen.

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.

 Tip 

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
Listing 45.7: Die Klasse PrintableObject

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