Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Neues in Java 7
2 Threads und nebenläufige Programmierung
3 Datenstrukturen und Algorithmen
4 Raum und Zeit
5 Dateien, Verzeichnisse und Dateizugriffe
6 Datenströme
7 Die eXtensible Markup Language (XML)
8 Dateiformate
9 Grafische Oberflächen mit Swing
10 Grafikprogrammierung
11 Netzwerkprogrammierung
12 Verteilte Programmierung mit RMI
13 RESTful und SOAP Web-Services
14 JavaServer Pages und Servlets
15 Applets
16 Datenbankmanagement mit JDBC
17 Technologien für die Infrastruktur
18 Reflection und Annotationen
19 Dynamische Übersetzung und Skriptsprachen
20 Logging und Monitoring
21 Java Native Interface (JNI)
22 Sicherheitskonzepte
23 Dienstprogramme für die Java-Umgebung
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
Java 7 - Mehr als eine Insel von Christian Ullenboom
Das Handbuch zu den Java SE-Bibliotheken
Buch: Java 7 - Mehr als eine Insel

Java 7 - Mehr als eine Insel
Rheinwerk Computing
1433 S., 2012, geb.
49,90 Euro, ISBN 978-3-8362-1507-7
Pfeil 18 Reflection und Annotationen
Pfeil 18.1 Metadaten
Pfeil 18.1.1 Metadaten durch JavaDoc-Tags
Pfeil 18.2 Metadaten der Klassen mit dem Class-Objekt
Pfeil 18.2.1 An ein Class-Objekt kommen
Pfeil 18.2.2 Was das Class-Objekt beschreibt *
Pfeil 18.2.3 Der Name der Klasse
Pfeil 18.2.4 instanceof mit Class-Objekten *
Pfeil 18.2.5 Oberklassen finden *
Pfeil 18.2.6 Implementierte Interfaces einer Klasse oder eines Interfaces *
Pfeil 18.2.7 Modifizierer und die Klasse Modifier *
Pfeil 18.2.8 Die Arbeit auf dem Feld *
Pfeil 18.3 Attribute, Methoden und Konstruktoren
Pfeil 18.3.1 Reflections – Gespür für die Attribute einer Klasse
Pfeil 18.3.2 Methoden einer Klasse erfragen
Pfeil 18.3.3 Properties einer Bean erfragen
Pfeil 18.3.4 Konstruktoren einer Klasse
Pfeil 18.3.5 Annotationen
Pfeil 18.4 Objekte erzeugen und manipulieren
Pfeil 18.4.1 Objekte erzeugen
Pfeil 18.4.2 Die Belegung der Variablen erfragen
Pfeil 18.4.3 Eine generische eigene toString()-Methode *
Pfeil 18.4.4 Variablen setzen
Pfeil 18.4.5 Bean-Zustände kopieren *
Pfeil 18.4.6 Private Attribute ändern
Pfeil 18.4.7 Methoden aufrufen
Pfeil 18.4.8 Statische Methoden aufrufen
Pfeil 18.4.9 Dynamische Methodenaufrufe bei festen Methoden beschleunigen *
Pfeil 18.5 Eigene Annotationstypen *
Pfeil 18.5.1 Annotationen zum Laden von Ressourcen
Pfeil 18.5.2 Neue Annotationen deklarieren
Pfeil 18.5.3 Annotationen mit genau einem Attribut
Pfeil 18.5.4 Element-Werte-Paare (Attribute) hinzufügen
Pfeil 18.5.5 Annotationsattribute vom Typ einer Aufzählung
Pfeil 18.5.6 Felder von Annotationsattributen
Pfeil 18.5.7 Vorbelegte Attribute
Pfeil 18.5.8 Annotieren von Annotationstypen
Pfeil 18.5.9 Deklarationen für unsere Ressourcen-Annotationen
Pfeil 18.5.10 Annotierte Elemente auslesen
Pfeil 18.5.11 Auf die Annotationsattribute zugreifen
Pfeil 18.5.12 Komplettbeispiel zum Initialisieren von Ressourcen
Pfeil 18.5.13 Mögliche Nachteile von Annotationen
Pfeil 18.6 Zum Weiterlesen

Rheinwerk Computing - Zum Seitenanfang

18.2 Metadaten der Klassen mit dem Class-ObjektZur nächsten Überschrift

Angenommen, wir wollen einen Klassen-Browser schreiben. Dieser soll alle zum laufenden Programm gehörenden Klassen und darüber hinaus weitere Informationen anzeigen, wie etwa Variablenbelegung, deklarierte Methoden, Konstruktoren und Informationen über die Vererbungshierarchie. Dafür benötigen wir die Bibliotheksklasse Class. Exemplare der Klasse Class sind Objekte, die entweder eine Java-Klasse oder Java-Schnittstelle repräsentieren (dass auch Schnittstellen durch Class-Objekte repräsentiert werden, wird im Folgenden nicht mehr ausführlich unterschieden).

In diesem Punkt unterscheidet sich Java von vielen herkömmlichen Programmiersprachen, da sich Eigenschaften von Klassen vom gerade laufenden Programm mittels der Class-Objekte abfragen lassen. Bei den Exemplaren von Class handelt es sich um eine eingeschränkte Form von Meta-Objekten[109](Echte Metaklassen wären Klassen, deren jeweils einziges Exemplar die normale Java-Klasse ist. Dann wären etwa die normalen Klassenvariablen in Wahrheit Objektvariablen in der Metaklasse.) – die Beschreibung einer Java-Klasse, die aber nur ausgewählte Informationen preisgibt. Neben normalen Klassen werden auch Schnittstellen durch je ein Class-Objekt repräsentiert.


Rheinwerk Computing - Zum Seitenanfang

18.2.1 An ein Class-Objekt kommenZur nächsten ÜberschriftZur vorigen Überschrift

Zunächst müssen wir für eine bestimmte Klasse das zugehörige Class-Objekt in Erfahrung bringen. Class-Objekte selbst kann nur die JVM erzeugen. Wir können das nicht (die Objekte sind immutable, und der Konstruktor ist privat).[110](Und der JavaDoc lautet: »Constructor. Only the Java Virtual Machine creates Class objects.«) Um einen Verweis auf ein Class-Objekt zu bekommen, bieten sich folgende Lösungen an:

  • Ist ein Exemplar der Klasse verfügbar, rufen wir die getClass()-Methode des Objekts auf und erhalten das Class-Exemplar der zugehörigen Klasse.
  • Jede Klasse enthält eine Klassenvariable mit dem Namen .class vom Typ Class, die auf das zugehörige Class-Exemplar verweist.
  • Auch auf primitiven Datentypen ist das Ende .class erlaubt. Das gleiche Class-Objekt liefert die statische Variable TYPE der Wrapper-Klassen. Damit ist int.class == Integer.TYPE.
  • Die Klassenmethode Class.forName(String) kann eine Klasse erfragen, und wir erhalten das zugehörige Class-Exemplar als Ergebnis. Ist die Klasse noch nicht geladen, sucht und bindet forName() die Klasse ein. Weil das Suchen schiefgehen kann, ist eine ClassNotFoundException möglich.
  • Haben wir bereits ein Class-Objekt, sind aber nicht an ihm, sondern an seinen Vorfahren interessiert, so können wir einfach mit getSuperclass() ein Class-Objekt für die Oberklasse erhalten.

Das folgende Beispiel zeigt drei Möglichkeiten auf, um an ein Class-Objekt für java.util.Date heranzukommen:

Listing 18.1: com/tutego/insel/meta/GetClassObject.java, main()

Class<Date> c1 = java.util.Date.class;
System.out.println( c1 ); // class java.util.Date
Class<?> c2 = new java.util.Date().getClass();
// oder Class<? extends Date> c2 = ...

System.out.println( c2 ); // class java.util.Date
try {
Class<?> c3 = Class.forName( "java.util.Date" );
System.out.println( c3 ); // class java.util.Date
}
catch ( ClassNotFoundException e ) { e.printStackTrace(); }

Die Variante mit forName() ist sinnvoll, wenn der Klassenname bei der Übersetzung des Programms noch nicht feststand. Sonst ist die vorhergehende Technik eingängiger, und der Compiler kann prüfen, ob es den Typ gibt.

Beispiel

Klassenobjekte für primitive Elemente liefert forName() nicht! Die beiden Anweisungen Class.forName("boolean") und Class.forName(boolean.class.getName()) führen zu einer ClassNotFoundException.

class java.lang.Object
  • final Class<? extends Object> getClass()
    Liefert zur Laufzeit das Class-Exemplar, das die Klasse des Objekts repräsentiert.
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • static Class<?> forName(String className) throws ClassNotFoundException
    Liefert das Class-Exemplar für die Klasse oder Schnittstelle mit dem angegebenen voll qualifizierten Namen. Falls sie bisher noch nicht vom Programm benötigt wurde, sucht und lädt der Klassenlader die Klasse. Die Methode liefert niemals null zurück. Falls die Klasse nicht geladen und eingebunden werden konnte, gibt es eine ClassNotFoundException. Eine alternative Methode forName() ermöglicht auch das Laden mit einem gewünschten Klassenlader. Der Klassenname muss immer voll qualifiziert sein.

ClassNotFoundException und NoClassDefFoundError *

Eine ClassNotFoundException lösen die Methoden forName() aus Class und loadClass() bzw. findSystemClass() aus ClassLoader immer dann aus, wenn der Klassenlader die Klasse nach ihrem Klassennamen nicht finden kann.

Neben der Exception-Klasse gibt es ein NoClassDefFoundError – ein harter LinkageError, den das System immer dann auslöst, wenn die JVM eine im Bytecode referenzierte Klasse nicht laden kann. Nehmen wir zum Beispiel eine Anweisung wie new MeineKlasse(). Führt die JVM diese Anweisung aus, versucht sie den Bytecode von MeineKlasse zu laden. Ist der Bytecode für MeineKlasse nach dem Compilieren entfernt worden, löst die JVM durch den nicht geglückten Ladeversuch den NoClassDefFoundError aus. Auch tritt der Fehler auf, wenn beim Laden des Bytecodes die Klasse MeineKlasse zwar gefunden wurde, aber MeineKlasse einen statischen Initialisierungsblock besitzt, der wiederum eine Klasse referenziert, für die keine Klassendatei vorhanden ist.

Während ClassNotFoundException häufiger vorkommt als NoClassDefFoundError, ist es im Allgemeinen ein Indiz dafür, dass ein Java-Archiv im Klassenpfad fehlt.

Umbenennungen der Klassennamen durch den Obfuscator

Dass der Compiler automatisch Bytecode gemäß dieses veränderten Quellcodes erzeugt, führt nur dann zu unerwarteten Problemen, wenn wir einen Obfuscator über den Programmtext laufen lassen, der nachträglich den Bytecode modifiziert und damit die Bedeutung des Programms beziehungsweise des Bytecodes verschleiert und dabei Klassen umbenennt. Offensichtlich darf ein Obfuscator Klassen, deren Class-Exemplare abgefragt werden, nicht umbenennen; oder der Obfuscator müsste die entsprechenden Zeichenketten ebenfalls korrekt ersetzen (aber natürlich nicht alle Zeichenketten, die zufällig mit Namen von Klassen übereinstimmen).


Rheinwerk Computing - Zum Seitenanfang

18.2.2 Was das Class-Objekt beschreibt *Zur nächsten ÜberschriftZur vorigen Überschrift

Ein Class-Exemplar kann eine Schnittstelle, eine Klasse, einen primitiven Datentyp oder auch einen Array-Typ beschreiben. Dies lässt sich durch die drei Methoden isInterface(), isPrimitive() und isArray() herausfinden. Wenn keine der drei Methoden für ein Class-Exemplar true liefert, repräsentiert das Objekt eine gewöhnliche Klasse.

Dass es auch Class-Exemplare gibt, die die primitiven Datentypen von Java beschreiben, erstaunt zunächst. Damit ist es jedoch möglich, die Parameter- und Ergebnistypen beliebiger Java-Methoden einheitlich durch Class-Exemplare zu beschreiben. Dazu kodieren jede der acht Wrapper-Klassen, die zu den Datentypen boolean, byte, char, short, int, long, float und double gehören, und die spezielle Klasse für den Typ void eine Konstante TYPE. Benötigen wir ein Class-Objekt für den primitiven Typ int, so greifen wir mit Integer.TYPE (oder alternativ mit int.class) darauf zu. Alle Class-Exemplare für primitive Datentypen werden automatisch von der JVM erzeugt. Die Methode isPrimitive() gibt genau für diese neun besonderen Class-Exemplare true zurück, sodass sie von Repräsentanten für echte Klassen unterschieden werden können.

Hinweis

Obwohl void kein Typ ist, meldet isPrimitive() dies:

System.out.println( void.class.isPrimitive() );  // true

Das folgende Programmstück testet die Attribute von Class-Objekten systematisch durch. Wir benutzen die Methode getName(), um den Namen des Class-Objekts auszugeben. Im nächsten Unterkapitel mehr dazu. Das Class-Objekt für Felder setzt sich aus dem Basistyp und Paaren von eckigen Klammern zusammen, etwa double[][].class.

Listing 18.2: com/tutego/insel/meta/CheckClassType.java, CheckClassType

class CheckClassType
{
public static void main( String[] args )
{
checkClassType( Observer.class );
checkClassType( Observable.class );
checkClassType( (new int[2][3][4]).getClass() );
checkClassType( Integer.TYPE );
}

static void checkClassType( Class<?> c )
{
if ( c.isArray() )
System.out.println( c.getName() + " ist ein Feld." );
else if ( c.isPrimitive() )
System.out.println( c + " ist ein primitiver Typ.");
else if ( c.isInterface() )
System.out.println( c.getName() + " ist ein Interface." );
else
System.out.println( c.getName() + " ist eine Klasse." );
}
}

Die Ausgabe des Programms ist nun:

java.util.Observer ist ein Interface.
java.util.Observable ist eine Klasse.
[[[I ist ein Feld.
int ist ein primitiver Typ.
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • boolean isInterface()
    Liefert true, wenn das Class-Objekt eine Schnittstelle beschreibt.
  • boolean isArray()
    Liefert true, wenn das Class-Objekt einen Array-Typ beschreibt.
  • boolean isPrimitive()
    Testet, ob das Class-Objekt einen primitiven Datentyp beschreibt.

Komponententyp bei Feldern

Die Methode getComponentType() liefert bei Feldern den Typ der Elemente als Class-Objekt. Steht das Class-Objekt für kein Feld, ist die Methodenrückgabe null.

System.out.println( double[].class.getComponentType() );    // double
System.out.println( double[][].class.getComponentType() ); // class [D
System.out.println( double.class.getComponentType() ); // null

Rheinwerk Computing - Zum Seitenanfang

18.2.3 Der Name der KlasseZur nächsten ÜberschriftZur vorigen Überschrift

Liegt zu einer Klasse das Class-Objekt vor, so können wir zur Laufzeit ihren voll qualifizierten Namen über die Methode getName() ausgeben. Da jeder Typ über einen Namen verfügt, führt diese Methode also jedes Mal zum Ziel:

Listing 18.3: SampleName.java

String n1 = new java.util.Date().getClass().getName();
System.out.println( n1 ); // java.util.Date
String n2 = java.util.RandomAccess.class.getName();
System.out.println( n2 ); // java.util.RandomAccess
String n3 = Deprecated.class.getName();
System.out.println( n3 ); // java.lang.Deprecated
String n4 = Thread.State.class.getName();
System.out.println( n4 ); // java.lang.Thread$State

Kodierung von Feldern *

Schwieriger ist die Kodierung bei Array-Typen, die ja eine besondere Form von Klassen sind. getName() kodiert sie mit einer führenden »[«. Jede Klammer steht dabei für eine Dimension des Array-Typs. Nach den Klammern folgt in einer kodierten Form der Typ der Array-Elemente. So liefert

System.out.println( int[][][].class.getName() );                // [[[I
System.out.println( (new int[2][3][4]).getClass().getName() ); // [[[I

den String »[[[I«, also einen dreidimensionalen Array-Typ mit Array-Elementen vom primitiven Typ int. Der Elementtyp ist wie folgt kodiert:

Tabelle 18.1: Kodierung der Elementtypen

Kürzel Datentyp

B

Byte

C

Char

D

Double

F

Float

I

Int

J

Long

LElementtyp;

Klasse oder Schnittstelle

S

Short

Z

Boolean

Nimmt das Array Objektreferenzen auf, wird deren Typ in der Form »LKlassenname;« kodiert. So liefert (new Object[3]).getClass().getName() den String [Ljava.lang.Object;. Der Klassen- beziehungsweise Schnittstellenname ist wie üblich voll qualifiziert.

Der String ist auch für Class.forName() von Bedeutung. Im Fall von Arrays liefert die Methode ein Class-Objekt für den Elementtyp. Die ersten Versuche, ein Class-Objekt für Felder zu beziehen, scheitern an einer ClassNotFoundException:

Class.forName( "String[]" );
Class.forName( "java.lang.String[]" );

In der ersten Anweisung ist der Klassenname nicht voll qualifiziert, und auch in der zweiten Anweisung ist der String falsch aufgebaut.

out.println( Class.forName("[Ljava.lang.String;") ); // class [Ljava.lang.String;

Steht die Frage an, ob ein Class-Objekt für ein Feld von Objekten steht oder für ein primitives Feld, lässt sich das Ergebnis von getName() auswerten:

public static boolean isObjectArray( Class clazz )
{
if ( clazz != null && clazz.isArray() )
return clazz.getName().startsWith( "[L" );
return false;
}

So liefert:

System.out.println( isObjectArray( Object[].class ) );       // true
System.out.println( isObjectArray( int[].class ) ); // false
System.out.println( isObjectArray( Object.class ) ); // false

toString()

Auch eine zweite Methode ist uns bekannt, um Class-Exemplare für Menschen lesbar auszugeben: die Methode toString(). Sie basiert im Kern auf getName(), fügt aber zusätzlich die Art der repräsentierten Klasse (normale Klasse, Schnittstelle oder primitiver Datentyp) ein:

public String toString() {
return (isInterface() ? "interface " :
(isPrimitive() ? "" : "class ")) + getName();
}
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • String getName()
    Liefert für ein Class-Exemplar als String den voll qualifizierten Namen der repräsentierten Klasse oder Schnittstelle beziehungsweise des repräsentierten Array-Typs oder des primitiven Datentyps.
  • String toString()
    Liefert eine für Menschen lesbare String-Repräsentation des Class-Objekts.

Rheinwerk Computing - Zum Seitenanfang

18.2.4 instanceof mit Class-Objekten *Zur nächsten ÜberschriftZur vorigen Überschrift

Der binäre Operator instanceof testet, ob ein Objekt Exemplar einer Klasse oder der Oberklasse ist. Wenn das Ergebnis wahr ist, lässt sich das Objekt unter dem gegebenen Typ ansprechen, ist also zuweisungskompatibel. Der rechte Operator bei instanceof, der Typname, muss jedoch immer zur Übersetzungszeit bekannt sein und kann nicht dynamisch, etwa durch einen String, festgelegt werden.

Ist der Typname zur Compilierzeit vielleicht unbekannt, kann das Class-Objekt helfen. Die Methode isInstance(Object) ist sozusagen ein dynamisches instanceof. Gilt mit dem Operator

object instanceof ReferenceType

so heißt das mit der Methode:

ReferenceType-Class-Objekt.isInstance( object )

Gewöhnungsbedürftig ist sicherlich die Tatsache, dass bei der Methode isInstance() die beiden Operanden umgedreht sind. Dazu ein paar Beispiele:

Listing 18.4: IsAssignableFrom.java, main()

Component b = new JLabel();
out.println( b instanceof JLabel ); // true
out.println( JLabel.class.isInstance( b ) ); // true
out.println( Object.class.isInstance( b ) ); // true
out.println( Class.forName("java.awt.Component").isInstance( b ) ); // true
out.println( String.class.isInstance( b ) ); // false

Die Methode isInstance(object) ist natürlich ein wenig dadurch eingeschränkt, dass es immer ein Test-Objekt geben muss. Die Frage etwa, ob das Class-Objekt der Schnittstelle PublicKey eine »Ist-eine-Art-von-Serializable« ist, kann isInstance(object) nicht beantworten, denn dann müsste es vorher ein Objekt geben. Für diesen Fall bietet das Class-Objekt noch eine zweite Methode, isAssignableFrom(Class):

Class<?> clazz = Serializable.class;
out.println( clazz.isAssignableFrom( String.class ) ); // true
out.println( clazz.isAssignableFrom( Thread.class ) ); // false
out.println( clazz.isAssignableFrom( PublicKey.class ) ); // true

Solange der Typname zur Übersetzungszeit bekannt ist, ist instanceof immer noch die beste Lösung. Doch wenn die Klasse nur durch ein Class-Objekt gegeben ist, bleibt immer noch isAssignableFrom(). Die Methode clazz.isInstance(obj) ist sozusagen eine Kurzform von clazz.isAssignableFrom(obj.getClass()).


Rheinwerk Computing - Zum Seitenanfang

18.2.5 Oberklassen finden *Zur nächsten ÜberschriftZur vorigen Überschrift

Das Class-Exemplar für eine Klasse gibt Zugriff auf die Oberklasse, die Sichtbarkeitsstufe und weitere Informationen. Die Oberklasse ermittelt getSuperclass(). Die Methode gibt null zurück, falls das Class-Objekt eine Schnittstelle repräsentiert oder wir schon am oberen Ende der Hierarchie sind, also bei dem Class-Objekt für die Wurzelklasse Object. Das folgende Programm findet alle Oberklassen einer Klasse durch den wiederholten Aufruf der Methode getSuperclass():

Listing 18.5: com/tutego/insel/meta/ShowSuperclasses.java

Class<?> subclass   = javax.swing.JButton.class;
Class<?> superclass = subclass.getSuperclass();

while ( superclass != null )
{
String className = superclass.getName();
System.out.println( className );
subclass = superclass;
superclass = subclass.getSuperclass();
}

Wahrscheinlich wäre eine rekursive Variante noch eleganter, aber darauf kommt es jetzt nicht an.

javax.swing.AbstractButton
javax.swing.JComponent
java.awt.Container
java.awt.Component
java.lang.Object
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • Class<? super T> getSuperclass()
    Liefert ein Class-Exemplar für die Oberklasse der Klasse, die durch das aufrufende Class-Objekt repräsentiert wird. Falls wir schon oben auf der Vererbungshierarchie bei Object sind oder nach der Oberklasse einer Schnittstelle fragen, liefert die Methode null.

Rheinwerk Computing - Zum Seitenanfang

18.2.6 Implementierte Interfaces einer Klasse oder eines Interfaces *Zur nächsten ÜberschriftZur vorigen Überschrift

Klassen stehen zum einen in einer Vererbungsbeziehung zu einer Oberklasse und können zum anderen mehrere Schnittstellen implementieren. Schnittstellen können ihrerseits wiederum andere Schnittstellen erweitern. Bei einer Klassendeklaration folgt direkt hinter dem Schlüsselwort implements eine Auflistung der implementierten Schnittstellen. So implementiert die Klasse RandomAccessFile die Schnittstellen DataOutput, DataInput und Closeable:

public class RandomAccessFile implements DataOutput, DataInput, Closeable

Um zu einem vorhandenen Class-Objekt die Schnittstellen aufzulisten, rufen wir getInterfaces() auf, die uns ein Array von Class-Objekten liefert. Von hier aus kennen wir den Weg zum Namen: Der Aufruf von getName() liefert den String für den Namen der Schnittstelle.

Beispiel

Gib die implementierten Schnittstellen von RandomAccessFile aus:

Listing 18.6: com/tutego/insel/meta/ShowInterfaces.java, main()

for ( Class<?> theInterface: java.io.RandomAccessFile.class.getInterfaces() )
System.out.println( theInterface.getName() );

Die Ausgabe ist:

java.io.DataOutput
java.io.DataInput
java.io.Closeable


Rheinwerk Computing - Zum Seitenanfang

18.2.7 Modifizierer und die Klasse Modifier *Zur nächsten ÜberschriftZur vorigen Überschrift

Eine Klassendeklaration kann Modifizierer enthalten, also Schlüsselwörter, die zum Beispiel die Sichtbarkeit bestimmen. Unter anderem sind dies public, protected, private und final. Sie stehen etwa in der Klassendeklaration vor dem Schlüsselwort class oder auch vor Methoden. Die Modifizierer können auch kombiniert werden: So ist die Klasse Class selbst public final. Die Methode getModifiers() liefert im Rückgabewert die Modifizierer, verschlüsselt als Ganzzahl:

System.out.println( Modifier.class.getModifiers() );                    // 1
System.out.println( Modifier.toString(Modifier.class.getModifiers()) ); // public
final class java.lang.Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
  • int getModifiers()
    Liefert die Modifizierer für eine Klasse oder eine Schnittstelle.

Dekodieren der Zahlrepräsentationen durch die Klasse Modifier

Damit wir uns bei der Entschlüsselung nicht mit magischen Zahlenwerten der JVM herumschlagen müssen, gibt es in der Klasse java.lang.reflect.Modifier einige statische Methoden, die diese Ganzzahl testen und aufbauen. Zudem werden Konstanten deklariert (wie Modifier.PUBLIC), mit denen dieser Integerwert verglichen werden kann. Da die Ganzzahl potenziell eine Kombination mehrerer Modifizierer kodiert, ist die gezielte Abfrage allerdings mit den statischen isXXX()-Methoden einfacher. Obwohl eine Klasse nicht transient, synchronized, nativ sein kann, listen wir hier alle statischen Methoden auf, da wir diese Modifizierer später auch für die Untersuchung von Methoden und Objekt- beziehungsweise Klassenvariablen per Reflection einsetzen. Jede dieser Testmethoden liefert true, wenn der gefragte Modifizierer in dem kodierten Ganzzahlwert enthalten ist. Alle Methoden sind static und liefern ein boolean-Ergebnis, außer toString().

class java.lang.reflect.Modifier
  • static boolean isAbstract(int mod)
  • static boolean isFinal(int mod)
  • static boolean isInterface(int mod)
  • static boolean isNative(int mod)
  • static boolean isPrivate(int mod)
  • static boolean isProtected(int mod)
  • static boolean isPublic(int mod)
  • static boolean isStatic(int mod)
  • static boolean isSynchronized(int mod)
  • static boolean isTransient(int mod)
  • static boolean isVolatile(int mod)

Betrachten wir die toString()-Methode der Klasse Modifier. Dort finden wir eine Liste aller möglichen Modifizierer mit den Konstanten:

public static String toString( int mod )
{
StringBuffer sb = new StringBuffer();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
if ((mod & PRIVATE) != 0) sb.append("private ");
if ((mod & PROTECTED) != 0) sb.append("protected ");
/* Canonical order */
if ((mod & ABSTRACT) != 0) sb.append("abstract ");
if ((mod & STATIC) != 0) sb.append("static ");
if ((mod & FINAL) != 0) sb.append("final ");
if ((mod & TRANSIENT) != 0) sb.append("transient ");
if ((mod & VOLATILE) != 0) sb.append("volatile ");
if ((mod & NATIVE) != 0) sb.append("native ");
if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized ");
if ((mod & INTERFACE) != 0) sb.append("interface ");

if ((len = sb.length()) > 0)/* trim trailing space */
return sb.toString().substring(0, len-1);
return "";
}

Des Weiteren gibt es seit Java 7 xxxModifier()-Methoden, die über ein int aussagen, welche Modifizierer an einem bestimmten Element erlaubt sind:

class java.lang.reflect.Modifier
  • static int classModifiers()
  • static int constructorModifiers()
  • static int fieldModifiers()
  • static int interfaceModifiers()
  • static int methodModifiers()
    Liefert ein int, das alle Modifizierer kodiert, die an Klassen/Konstruktoren/Feldern/Schnittstellen/Methoden erlaubt sind. So liefert constructorModifiers() zum Beispiel Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE.
Hinweis

Schnittstellen, wie java.io.Serializable, tragen den Modifier abstract.

int modifier = Serializable.class.getModifiers();
out.println( modifier ); // 1537
out.println( Modifier.toString(modifier) ); // public abstract interface


Rheinwerk Computing - Zum Seitenanfang

18.2.8 Die Arbeit auf dem Feld *Zur vorigen Überschrift

Die Utility-Klasse java.lang.reflect.Array stellt statische Methoden bereit, um auf Array-Objekten generisch zu arbeiten. Elemente lassen sich erfragen und setzen und auch Arrays mit einem gewünschten Typ anlegen:

Object array = Array.newInstance( int.class, 20 );
System.out.println( Array.getLength(array) ); // 20
Array.setInt
( array, 0, –1 );
System.out.println( Array.getInt(array, 0) ); // –1

Bei newInstance() ist der Typ int.class und nicht int[].class!

Eine allgemeine statische Array-Methode set() und get() arbeitet für Objekte, wobei auch Wrapper für primitive Felder verwendet werden können:

Array.set( array, 0, Integer.valueOf(-1) );
System.out.println( Array.get(array, 0) ); // –1

Für mehrdimensionale Felder lässt sich bei newInstance() ein Feld von Größen angeben:

Object array = Array.newInstance( int.class, new int[]{ 2, 2 } );
((int[][])array)[0][0] = 1;
((int[][])array)[1][1] = 1;
System.out.println( Arrays.deepToString( (int[][])array ) ); // [[1, 0], [0, 1]]


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Neuauflage: Java SE 8 Standard-Bibliothek
Neuauflage: Java SE 8 Standard-Bibliothek
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Java EE 7






 Professionell
 entwickeln mit
 Java EE 7


Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Einstieg in Eclipse






 Einstieg in Eclipse


Zum Katalog: Einstieg in Java






 Einstieg in Java


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2012
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de