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 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 17 Typen, Reflection und Annotationen
Pfeil 17.1 Metadaten
Pfeil 17.1.1 Metadaten durch Javadoc-Tags
Pfeil 17.2 Metadaten der Typen mit dem Class-Objekt
Pfeil 17.2.1 An ein Class-Objekt kommen
Pfeil 17.2.2 Eine Class ist ein Type
Pfeil 17.3 Klassenlader
Pfeil 17.3.1 Das Verzeichnis jre/lib/endorsed *
Pfeil 17.3.2 Die Klasse java.lang.ClassLoader
Pfeil 17.3.3 Hot Deployment mit dem URL-Classloader *
Pfeil 17.4 Metadaten der Typen mit dem Class-Objekt
Pfeil 17.4.1 Der Name des Typs
Pfeil 17.4.2 Was das Class-Objekt beschreibt *
Pfeil 17.4.3 instanceof mit Class-Objekten *
Pfeil 17.4.4 Oberklassen finden *
Pfeil 17.4.5 Implementierte Interfaces einer Klasse oder eines Interfaces *
Pfeil 17.4.6 Modifizierer und die Klasse Modifier *
Pfeil 17.4.7 Die Arbeit auf dem Feld *
Pfeil 17.5 Attribute, Methoden und Konstruktoren
Pfeil 17.5.1 Reflections – Gespür für die Attribute einer Klasse
Pfeil 17.5.2 Schnittstelle Member für Eigenschaften
Pfeil 17.5.3 Field-Klasse
Pfeil 17.5.4 Methoden einer Klasse erfragen
Pfeil 17.5.5 Properties einer Bean erfragen
Pfeil 17.5.6 Konstruktoren einer Klasse
Pfeil 17.5.7 Annotationen
Pfeil 17.6 Objekte erzeugen und manipulieren
Pfeil 17.6.1 Objekte erzeugen
Pfeil 17.6.2 Die Belegung der Variablen erfragen
Pfeil 17.6.3 Eine generische eigene toString()-Methode *
Pfeil 17.6.4 Variablen setzen
Pfeil 17.6.5 Bean-Zustände kopieren *
Pfeil 17.6.6 Private Attribute ändern
Pfeil 17.6.7 Methoden aufrufen
Pfeil 17.6.8 Statische Methoden aufrufen
Pfeil 17.6.9 Dynamische Methodenaufrufe bei festen Methoden beschleunigen *
Pfeil 17.6.10 java.lang.reflect.Parameter
Pfeil 17.7 Eigene Annotationstypen *
Pfeil 17.7.1 Annotationen zum Laden von Ressourcen
Pfeil 17.7.2 Neue Annotationen deklarieren
Pfeil 17.7.3 Annotationen mit genau einem Attribut
Pfeil 17.7.4 Element-Wert-Paare (Attribute) hinzufügen
Pfeil 17.7.5 Annotationsattribute vom Typ einer Aufzählung
Pfeil 17.7.6 Felder von Annotationsattributen
Pfeil 17.7.7 Vorbelegte Attribute
Pfeil 17.7.8 Annotieren von Annotationstypen
Pfeil 17.7.9 Deklarationen für unsere Ressourcen-Annotationen
Pfeil 17.7.10 Annotierte Elemente auslesen
Pfeil 17.7.11 Auf die Annotationsattribute zugreifen
Pfeil 17.7.12 Komplettbeispiel zum Initialisieren von Ressourcen
Pfeil 17.7.13 Mögliche Nachteile von Annotationen
Pfeil 17.8 Zum Weiterlesen
 
Zum Seitenanfang

17.3Klassenlader Zur vorigen ÜberschriftZur nächsten Überschrift

In Java ist eine Kaskade von unterschiedlichen Klassenladern für das Laden von Klassen verantwortlich. Bei Java arbeiten mehrere Klassenlader in einer Kette zusammen. An erster Stelle steht der Klassenlader für alle »Kern«-Klassen, wie Object, String, der Bootstrap-Klassenlader. Findet der eine gewünschte Klasse nicht, geht die Anfrage weiter an einen Klassenlader, der im Extension-Verzeichnis lib/ext schaut. Wenn eine Klasse auch dort nicht zu finden ist, folgt die Suche über den benutzerdefinierten Klassenpfad und eigene Klassenlader.

Abfragen des Klassenpfades

Ob der eigene Klassenpfad überhaupt gesetzt ist, ermittelt ein einfaches echo %CLASSPATH% (Windows) bzw. echo $CLASSPATH (Unix).

Zur Laufzeit steht der normale Klassenpfad in der System-Property java.class.path. Auch der Bootstrap-Klassenpfad kann ausgelesen werden über die Variable sun.boot.class.path. Zusätzliche Erweiterungsverzeichnisse lassen sich über die Systemeigenschaft java.ext.dirs auslesen.

Eigenschaft

Beispielbelegung

java.class.path

C:\Users\Christian\Insel\programme\2_18_Reflection_Annotationen

java.ext.dirs

C:\Program Files\Java\jdk1.8.0\jre\lib\ext;C:\WINDOWS\Sun\Java\ lib\ext

sun.boot.class.path

C:\Program Files\Java\jdk1.8.0\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.8.0\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0\jre\classes

Tabelle 17.1Mögliche Ausgaben von com/tutego/insel/lang/ClasspathDir.java

[»]Hinweis

Wird die JVM über java -jar aufgerufen, beachtet sie nur Klassen in dem genannten JAR und ignoriert den Klassenpfad.

 
Zum Seitenanfang

17.3.1Das Verzeichnis jre/lib/endorsed * Zur vorigen ÜberschriftZur nächsten Überschrift

Im Fall der XML-Parser und weiterer Bibliotheken kommt es häufiger vor, dass sich die Versionen einmal ändern. Es wäre nun müßig, aus diesem Grund die neuen Bibliotheken immer im bootclasspath aufzunehmen, da dann immer eine Einstellung über die Kommandozeile stattfände. Die Entwickler haben daher für spezielle Pakete ein Verzeichnis vorgesehen, in dem Updates eingelagert werden können: das Verzeichnis jre/lib/endorsed der Java-Installation. Alternativ können die Klassen und Archive auch durch die Kommandozeilenoption java.endorsed.dirs spezifiziert werden.

Wenn der Klassenlader im Verzeichnis endorsed eine neue Version – etwa vom XML-Parser – findet, lädt er die Klassen von dort und nicht aus dem JAR-Archiv, aus dem sonst die Klassen geladen würden. Standardmäßig bezieht er die Ressourcen aus der Datei rt.jar. Alle im Verzeichnis endorsed angegebenen Typen überdecken somit die Standardklassen aus der Java SE; neue Versionen lassen sich einfach einspielen.

Nicht alle Klassen lassen sich mit endorsed überdecken. Zum Beispiel lässt sich keine neue Version von java.lang.String einfügen. Die Dokumentation »Endorsed Standards Override Mechanism« unter http://docs.oracle.com/javase/8/docs/technotes/guides/standards/ zeigt die überschreibbaren Pakete an: javax.rmi.CORBA, org.omg.*, org.w3c.dom und org.xml.*. (Im Übrigen definiert auch Tomcat, die Servlet-Engine, ein solches Überschreibverzeichnis. Hier können wir Klassen in das Verzeichnis common/lib/endorsed aufnehmen, die dann beim Start von Tomcat die Standardklassen überschreiben.)

 
Zum Seitenanfang

17.3.2Die Klasse java.lang.ClassLoader Zur vorigen ÜberschriftZur nächsten Überschrift

Jeder Klassenlader in Java ist vom Typ java.lang.ClassLoader. Die Methode loadClass(…) erwartet einen so genannten »binären Namen«, der an den voll qualifizierten Klassennamen erinnert.

abstract class java.lang.ClassLoader
  • protected Class<?> loadClass(String name, boolean resolve)
    Lädt die Klasse und bindet sie mit resolveClass(…) ein, wenn resolve gleich true ist.

  • public Class<?> loadClass(String name)
    Die öffentliche Methode ruft loadClass(name, false) auf, was bedeutet, dass die Klasse nicht standardmäßig angemeldet (gelinkt) wird. Beide Methoden können eine ClassNotFoundException auslösen.

Die geschützte Methode führt anschließend drei Schritte durch:

  1. Wird loadClass(…) auf einer Klasse aufgerufen, die dieser Klassenlader schon eingelesen hat, so kehrt die Methode mit dieser gecachten Klasse zurück.

  2. Ist die Klasse nicht gespeichert, darf zuerst der Vater (parent class loader) versuchen, die Klasse zu laden.

  3. Findet der Vater die Klasse nicht, so darf jetzt der Klassenlader selbst mit findClass(…) versuchen, die Klasse zu beziehen.

Eigene Klassenlader überschreiben in der Regel die Methode findClass(…), um nach einem bestimmten Schema zu suchen, etwa nach Klassen aus der Datenbank. In diesen Stufen ist es auch möglich, höher stehende Klassenlader zu umgehen, was beispielsweise bei Servlets Anwendung findet.

Neue Klassenlader

Java nutzt an den verschiedensten Stellen spezielle Klassenlader, etwa für Applets den sun.applet.AppletClassLoader. Für uns ist der java.net.URLClassLoader interessant, da er Klassen von beliebigen URLs laden kann und die Klassen nicht im klassischen Klassenpfad benötigt. Wie ein eigener Klassenlader aussieht, zeigt das Beispiel unter http://tutego.com/go/urlclassloader, das den URL-Classloader vom Prinzip her nachimplementiert.

Klassenhierarchie von URLClassLoader

Abbildung 17.1Klassenhierarchie von URLClassLoader

 
Zum Seitenanfang

17.3.3Hot Deployment mit dem URL-Classloader * Zur vorigen ÜberschriftZur nächsten Überschrift

Unter Hot Deployment ist die Möglichkeit zu verstehen, zur Laufzeit Klassen auszutauschen. Diese Möglichkeit ist für viele EJB- oder Servlet-Container wichtig, da sie im Dateisystem auf eine neue Klassendatei warten und im gegebenen Fall die alte Klasse durch eine neue ersetzen. Ein Servlet-Container überwacht geladene Klassen und lädt sie bei Änderungen neu. Eine Internetsuche mit dem Stichwort AdaptiveClassLoader listet Implementierungen auf.

Damit dieser heiße Wechsel funktioniert, muss die Klasse über einen neuen Klassenlader bezogen werden. Das liegt daran, dass der Standardklassenlader von Haus aus keine Klasse mehr loswird, wenn er sie einmal geladen hat. Mit anderen Worten: Wenn eine Klasse über Class.forName(Klasse) angefordert wird, ist sie immer im Cache und wird nicht mehr entladen. Ein neuer Klassenlader fängt immer von vorn an, wenn er die Klasse für sich zum ersten Mal sieht.

Mit immer neuen Klassenladern funktioniert das Neuladen, weil für eine neue Klasse dann jeweils ein eigener Klassenlader zuständig ist. Ändert sich die Klasse, wird ein neuer Klassenlader konstruiert, der die neue Klasse lädt. Doch damit ist die alte Klasse noch nicht aus dem Spiel. Nur wenn sich niemand mehr für die alte Klasse und für den Klassenlader interessiert, kann die Laufzeitumgebung diese nicht benutzten Objekte erkennen und aufräumen.

Gleiche Klasse mehrfach laden

Wir wollen im Folgenden eine eigene statische Methode newInstance() vorstellen, die beim Aufruf die neueste Version des Dateisystems lädt und ein Exemplar bildet. Die neu zu ladende Klasse soll ohne Beschränkung der Allgemeinheit einen Standard-Konstruktor haben – andernfalls muss über Reflection ein parametrisierter Konstruktor aufgerufen werden; wir wollen das Beispiel aber kurz halten.

Beginnen wir mit der Klasse, die zweimal geladen werden soll. Sie besitzt einen statischen Initialisierungsblock, der etwas auf der Konsole ausgibt, wenn er beim Laden ausgeführt wird:

Listing 17.2com/tutego/insel/lang/ClassToLoadMultipleTimes.java

package com.tutego.insel.lang;

public class ClassToLoadMultipleTimes {
static {
System.out.println( "ClassToLoadMultipleTimes" );
}
}

Die Testklasse legen wir unter C:\ ab, und zwar so, dass die Verzeichnisstruktur durch das Paket erhalten bleibt – demnach unter C:\com\tutego\insel\lang.

Jetzt brauchen wir noch eine Testklasse, die ClassToLoadMultipleTimes unter dem Wurzelverzeichnis liest (also etwa unter C:/):

Listing 17.3com/tutego/insel/lang/LoadClassMultipleTimes.java

package com.tutego.insel.lang;

import java.io.File;
import java.net.*;

public class LoadClassMultipleTimes {

public static Object newInstance( String path, String classname ) throws Exception {
URL url = Paths.get( path ).toUri().toURL();
try ( URLClassLoader cl = new URLClassLoader( new URL[]{ url } ) ) {
Class<?> c = cl.loadClass( classname );
return c.newInstance();
}
}

public static void main( String[] args ) throws Exception {
newInstance( "/", "com.tutego.insel.lang.ClassToLoadMultipleTimes" );
newInstance( "/", "com.tutego.insel.lang.ClassToLoadMultipleTimes" );
}
}

Nach dem direkten Start ohne Vorbereitung bekommen wir nur einmal die Ausgabe – anders als erwartet. Der Grund liegt in der Hierarchie der Klassenlader. Wichtig ist hier, dass der Standardklassenlader die Klasse ClassToLoadMultipleTimes nicht »sehen« darf. Wir müssen die Klasse also aus dem Zugriffspfad der Laufzeitumgebung löschen, da andernfalls aufgrund des niedrigen Rangs unser eigener URL-Klassenlader nicht zum Zuge kommt. (Und ist die Klassendatei nicht im Pfad, können wir das praktische ClassToLoadMultipleTimes.class.getName() nicht nutzen.) Erst nach dem Löschen werden wir Zeuge, wie die virtuelle Maschine auf der Konsole die beiden Meldungen ausgibt, wenn der statische Initialisierungsblock ausgeführt wird.

Die zu ladende Klasse darf nicht den gleichen voll qualifizierten Namen wie eine Standardklasse (etwa java.lang.String) tragen. Das liegt daran, dass auch in dem Fall, in dem die Klasse mit dem eigenen URLClassLoader bezogen werden soll, die Anfrage trotzdem erst an den System-Klassenlader, dann an den Erweiterungs-Klassenlader und erst ganz zum Schluss an unseren eigenen Klassenlader geht. Es ist also nicht möglich, aus einem Java-Programm Klassen zu beziehen, die prinzipiell vom System-Klassenlader geladen werden. Wir können eine Klasse wie javax.swing. JButton nicht selbst beziehen. Wenn sie mit einem Klassenlader ungleich unserem eigenen geladen wird, hat dies wiederum zur Folge, dass wir die geladene Klasse nicht mehr loswerden – was allerdings im Fall der Systemklassen kein Problem sein sollte.

Implementiert die Klasse eine bestimmte Schnittstelle oder erbt sie von einer Basisklasse, lässt sich der Typ der Rückgabe unserer Methode newInstance() einschränken. Auf diese Weise ist ein Plugin-Prinzip realisierbar: Die geladene Klasse bietet mit dem Typ Methoden an. Während dieser Typ bekannt ist (der implizite Klassenlader besorgt sie), wird die Klasse selbst erst zur Laufzeit geladen (expliziter Klassenlader).

Einzigartigkeit eines Singletons

Ein Singleton ist ein Erzeugermuster, das ein Exemplar nur einmal hervorbringt. Singletons finden sich in der JVM an einigen Stellen; so gibt es java.lang.Runtime nur einmal, genauso wie java.awt.Toolkit. Auch Aufzählungen sind Singletons, und so lassen sie sich problemlos mit == vergleichen. Und doch gibt es zwischen den Bibliotheks-Singletons und den von Hand gebauten Singleton-Realisierungen und Aufzählungen einen großen Unterschied: Sie basieren alle auf statischen Variablen, die dieses eine Exemplar referenzieren. Damit ist eine Schwierigkeit verbunden. Denn wie wir an den Beispielen mit dem URLClassLoader gesehen haben, ist dieses Exemplar immer nur pro Klassenlader einzigartig, aber nicht in der gesamten JVM an sich, die eine unbestimmte Anzahl von Klassenladern nutzen kann. Die Java-Aufzählungen sind ein gutes Beispiel. In einem Server kann es zwei gleiche Weekday-Aufzählungen im gleichen Paket geben. Und doch sind sie völlig unterschiedlich und miteinander inkompatibel, wenn sie zwei unterschiedliche Klassenlader einlesen. Selbst die Class-Objekte dieser Aufzählungen, die ja auch Singletons innerhalb eines Klassenladers sind, sind bei zwei verschiedenen Klassenladern nicht identisch. Globale Singletons für die gesamte JVM gibt es nicht – zum Glück. Auf der anderen Seite verursachen diese Klassen-Phantome viele Probleme in Java EE-Umgebungen. Doch das ist eine andere Geschichte für ein Java EE-Buch.

class java.net.URLClassLoader
extends SecureClassLoader
  • URLClassLoader(URL[] urls)
    Erzeugt einen neuen URLClassLoader für ein Feld von URLs mit dem Standard-Vater-Klassenlader.

  • URLClassLoader(URL[] urls, ClassLoader parent)
    Erzeugt einen neuen URLClassLoader für ein Feld von URLs mit einem gegebenen Vater-Klassenlader.

  • protected void addURL(URL url)
    Fügt eine URL hinzu.

  • URL[] getURLs()
    Liefert die URLs.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook 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

Cookie-Einstellungen ändern