Jede Klasse in Java ist Bestandteil eines Pakets. Der vollständige Name einer Klasse besteht aus dem Namen des Pakets, gefolgt von einem Punkt, der vom eigentlichen Namen der Klasse gefolgt wird. Der Name des Pakets selbst kann ebenfalls einen oder mehrere Punkte enthalten.
Um eine Klasse verwenden zu können, muß angegeben werden, in welchem Paket sie liegt. Hierzu gibt es zwei unterschiedliche Möglichkeiten:
java.util.Date d = new java.util.Date();
import java.util.*; ... Date d = new Date();
Die Verwendung voll qualifizierter Namen hat den Nachteil, daß die Klassennamen sehr lang und unhandlich werden. Bequemer ist daher die Anwendung der zweiten Variante, bei der die benötigten Klassen mit Hilfe einer import-Anweisung dem Compiler bekannt gemacht werden.
Die import-Anweisung gibt es in zwei unterschiedlichen Ausprägungen:
import java.util.Date; ... Date d = new Date(); java.util.Vector = new java.util.Vector();
import java.util.*; ... Date d = new Date(); Vector v = new Vector();
|
|
Im Gegensatz zu ähnlichen Konstrukten in anderen Sprachen ist die Verwendung der zweiten Variante der import-Anweisung nicht zwangsläufig wesentlich ineffizienter als die der ersten. In der Sprachspezifikation wird sie als type import on demand bezeichnet, was bedeutet, daß die Klasse erst dann in den angegebenen Paketen gesucht wird, wenn das Programm sie wirklich benötigt. Keinesfalls muß der Compiler beim Parsen der import-Anweisung zwangsläufig alle Klassendateien des angegebenen Pakets in den Hauptspeicher laden oder ähnlich zeit- und speicheraufwendige Dinge machen. Es schadet also im allgemeinen nichts, die zweite Variante der import-Anweisung zu verwenden. |
In vielen verschiedenen Beispielen in diesem Buch werden Klassennamen (wie beispielsweise String, Thread oder Object) verwendet, ohne daß eine zugehörige import-Anweisung zu erkennen wäre. In diesem Fall entstammen die Klassen dem Paket java.lang.
Dieses Paket wurde von den Entwicklern der Sprache als so wichtig angesehen, daß es von jeder Klasse automatisch importiert wird. Man kann sich das so vorstellen, als wenn am Anfang jeder Quelldatei implizit die folgende Anweisung stehen würde:
import java.lang.*;
|
|
Ein expliziter Import von java.lang ist daher niemals nötig. Alle anderen Pakete müssen jedoch vor ihrer Verwendung importiert werden, wenn auf die Anwendung voll qualifizierter Klassennamen verzichtet werden soll. |
Während beim Wechsel von der Version 1.0.X auf 1.1.X die Sprachspezifikation relativ stabil geblieben ist, hat sich der Umfang der Laufzeitbibliothek um ein Vielfaches erhöht. Dies zeigt sich unter anderem an der gestiegenen Anzahl an vordefinierten Paketen, die mit dem JDK ausgeliefert werden (s. Tabelle 8.1).
|
Paket |
Bedeutung |
| java.applet | Applets |
| java.awt | Abstract Windowing Toolkit |
| java.awt.datatransfer | AWT Clipboard-Funktionen |
| java.awt.event | AWT Event-Handling |
| java.awt.image | AWT Bildverarbeitung |
| java.beans | Java Beans |
| java.io | Bildschirm- und Datei-I/O |
| java.lang | Elementare Sprachunterstützung |
| java.lang.reflect | Reflection-API |
| java.math | Fließkomma-Arithmetik |
| java.net | Netzwerkunterstützung |
| java.rmi | Remote Method Invocation (RMI) |
| java.rmi.dgc | RMI Distributed Garbage Collection |
| java.rmi.registry | RMI Service Registry |
| java.rmi.server | RMI-Support |
| java.security | Security-Dienste |
| java.security.acl | Access Control Lists |
| java.security.interfaces | DSA-Interfaces |
| java.sql | Datenbankzugriff (JDBC) |
| java.text | Internationalisierung |
| java.util | Diverse Utilities und Datenstrukturen |
| java.util.zip | JAR-Files, Kompression, Prüfsummen |
Wie bereits mehrfach zu sehen war, bestehen Paketnamen in Java aus mehreren Komponenten, die jeweils durch einen Punkt voneinander getrennt sind. Neben der Aufgabe, die Paketnamen visuell zu strukturieren, hat die Unterteilung aber noch eine andere, sehr viel wichtigere Bedeutung.
Jeder Teil eines mehrstufigen Paketnamens bezeichnet nämlich ein Unterverzeichnis auf dem Weg zu der gewünschten Klassendatei. Soll beispielsweise das Paket java.awt.image eingebunden werden, sucht der Java-Compiler es im Unterverzeichnis java\awt\image. Interessant ist in diesem Zusammenhang natürlich die Frage, in welchem Verzeichnis der Compiler mit der Suche beginnt.
Auf diese Frage gibt es mehrere Antworten:
Anders als im JDK 1.0.X ist es bei einer Standardinstallation des JDK 1.1.X unter Windows 95 nicht erforderlich, den CLASSPATH explizit zu setzen. Alle Tools generieren den CLASSPATH implizit aus der Position des bin-Verzeichnisses (z.B. c:\java1.1.2\bin) nach folgendem Schema:
.;[bin]\..\classes;[bin]\..\lib\classes.zip
[bin] steht hier für den Pfad des bin-Verzeichnisses. Nur wenn die Klassendateien in einem anderen Verzeichnis liegen, muß die CLASSPATH-Variable manuell geändert werden.
Im Java-Installationsverzeichnis findet man meist eine Datei classes.zip anstelle der erwähnten Unterverzeichnisse mit den Klassendateien. Aus Gründen der Performance beim Übersetzen haben sich die Entwickler entschlossen, alle Standardklassendateien in diesem Archiv abzulegen, um einen schnelleren Lesezugriff zu erhalten.
|
|
Die Datei classes.zip sollte keinesfalls ausgepackt werden, denn der Compiler kann sie in archivierter Form verwenden. Dies wurde dadurch erleichtert, daß beim Packen der Klassen auf die Komprimierung verzichtet wurde. Die Archivierung bietet so zwar lediglich den Vorteil, mehrere unterschiedliche Dateien in einer einzigen großen zusammenzufassen, aber dadurch entfallen zeitaufwendige Verzeichniszugriffe, wenn der Compiler nach Klassennamen suchen muß oder den Inhalt einer Klassendatei laden will. |
Um diese Art der Speicherung der Klassendateien dem Compiler bekannt zu machen, muß in der CLASSPATH-Umgebungsvariable nicht nur das Verzeichnis, sondern auch der Name der .zip-Datei angegeben werden, z.B.:
CLASSPATH=.;c:\java\LIB\CLASSES.ZIP
Die Entwickler von Java haben sich einen Mechanismus ausgedacht, um auch bei sehr großen Projekten, an denen möglicherweise sehr viele Entwickler beteiligt sind, mögliche Namenskollisionen zwischen den beteiligten Klassen und Paketen zu vermeiden. Auch die Verwendung einer großen Anzahl unterschiedlicher Klassenbibliotheken von verschiedenen Herstellern sollte möglich sein, ohne daß Namensüberschneidungen dies schon im Keim ersticken.
Um diese Probleme zu lösen, hat sich das Java-Team eine Vorgehensweise zur Vergabe von Paketnamen überlegt, die an das Domain-Namen-System bei Internet-Adressen angelehnt ist. Danach sollte jeder Anbieter seine Pakete entsprechend dem eigenen Domain-Namen benennen, dabei allerdings die Namensbestandteile in umgekehrter Reihenfolge verwenden. Einzige Ausnahme zu diesem Namensschema sind die Klassen java.*, die im Standardumfang einer Java-Installation enthalten sind.
So sollten beispielsweise die Klassen der Firma Sun, deren Domain-Name sun.com ist, in einem Paket com.sun oder in darunter befindlichen Subpaketen liegen. Da die Domain-Namen weltweit eindeutig sind, werden Namenskollisionen zwischen Paketen unterschiedlicher Hersteller auf diese Weise von vornherein vermieden.
Unterhalb des Basispakets können Unterpakete beliebig geschachtelt werden. Die Namensvergabe liegt dabei in der Entscheidung des Unternehmens. Gibt es beispielsweise die Abteilungen FE, KIS und RIS in einem Unternehmen mit der Domain prompt.de, kann es sinnvoll sein, diese Abteilungsnamen auch als Unterprojekte zu verwenden. Die von diesen Abteilungen erstellten Klassen würden dann in den Paketen de.prompt.fe, de.prompt.kis und de.prompt.ris liegen.
Der Vollständigkeit halber sollte man anmerken, daß das hier beschriebene System sich in der Praxis noch nicht vollständig durchgesetzt hat und insbesondere die Klassen der java.*-Hierarchie eine Ausnahme bilden. Es wird mit der zunehmenden Anzahl allgemein verfügbarer Pakete jedoch an Bedeutung gewinnen.
Bisher wurde nur gezeigt, wie man Klassen aus fremden Paketen verwendet, nicht aber, wie man selbst Pakete erstellt. Dies ist aber glücklicherweise keine Aufgabe für Spezialisten, sondern sehr einfach mit Bordmitteln realisierbar.
Um eine Klasse einem ganz bestimmten Paket zuzuordnen, muß lediglich am Anfang des Quelltextes eine geeignete package-Anweisung verwendet werden. Diese besteht (analog zur import-Anweisung) aus dem Schlüsselwort package und dem Namen des Pakets, dem die nachfolgende Klasse zugeordnet werden soll. Die package-Anweisung muß als erste Anweisung in einer Quelldatei stehen, so daß der Compiler sie noch vor den import-Anweisungen findet.
Der Aufbau und die Bedeutung der Paketnamen in der package-Anweisung entspricht exakt dem der import-Anweisung. Der Compiler löst ebenso wie beim import den dort angegebenen hierarchischen Namen in eine Kette von Unterverzeichnissen auf, an deren Ende die Quelldatei steht. Neben der Quelldatei wird auch die Klassendatei in diesem Unterverzeichnis erstellt.
Da der Java-Compiler eingebundene Quelldateien, die noch nicht übersetzt sind, während der Übersetzung einer anderen Klasse automatisch mit übersetzt, ist das Erstellen eines neuen Pakets sehr einfach. Wir wollen uns ein Beispiel ansehen, bei dem zwei Pakete demo und demo.tools angelegt werden und die darin enthaltenen Klassen A und B bzw. C in einer Klasse Example0801 verwendet werden. Am einfachsten ist es, in den folgenden Schritten vorzugehen:
Wir gehen davon aus, daß der CLASSPATH das aktuelle Verzeichnis enthält (also beispielsweise den Inhalt .;c:\java\LIB\CLASSES.ZIP hat) und legen im aktuellen Verzeichnis die Unterverzeichnisse demo und demo\tools an.
package demo;
public class A
{
public void hello()
{
System.out.println("Hier ist A");
}
}
Sie enthält die Anweisung package demo;, um anzuzeigen, daß die Klasse A zum Paket demo gehört.
package demo;
public class B
{
public void hello()
{
System.out.println("Hier ist B");
}
}
Auch diese Quelldatei enthält die Anweisung package demo;, um anzuzeigen, daß die Klasse zum Paket demo gehört.
package demo.tools;
public class C
{
public void hello()
{
System.out.println("Hier ist C");
}
}
Diese Quelldatei enthält die Anweisung package demo.tools;, um anzuzeigen, daß die Klasse zum Paket demo.tools gehört.
import demo.*;
import demo.tools.*;
public class Example0801 {
public static void main(String[] args)
{
(new A()).hello();
(new B()).hello();
(new C()).hello();
}
}
Ohne vorher die Klassen A, B oder C separat übersetzen zu müssen, kann nun einfach Example0801 kompiliert werden. Der Compiler erkennt die Verwendung von A, B und C, findet die Paketverzeichnisse demo und demo\tools und erkennt, daß die Quellen noch nicht übersetzt sind. Er erzeugt dann aus den .java-Dateien die zugehörigen .class-Dateien, bindet sie ein und übersetzt schließlich die Klasse Example0801.
Würde nur dann ein eigenes Paket erzeugt werden, wenn die Quelldatei eine package-Anweisung enthält, müßte man sich fragen, zu welchem Paket die Klassen gehören, in deren Quelldatei die package-Anweisung fehlt (was ja erlaubt ist). Die Antwort auf diese Frage liegt darin, daß es in Java ein Default-Paket gibt, das genau dann verwendet wird, wenn keine andere Zuordnung getroffen wurde.
Das Default-Paket ist ein Zugeständnis an kleinere Programme oder einfache Programmierprojekte, bei denen es sich nicht lohnt, eigene Pakete anzulegen. Ohne Teile des Projektes in Unterverzeichnissen abzulegen und durch import- und package-Anweisungen unnötigen Aufwand zu treiben, ist es auf diese Weise möglich, Quelldateien einfach im aktuellen Verzeichnis abzulegen, dort zu kompilieren und automatisch einzubinden. Klassen des Default-Pakets können ohne explizite import-Anweisung verwendet werden.
Es gibt noch eine wichtige Besonderheit bei der Deklaration von Klassen, die von anderen Klassen verwendet werden sollen. Damit eine Klasse A eine andere Klasse B einbinden darf, muß nämlich eine der beiden folgenden Bedingungen erfüllt sein:
|
|
Wenn also nur Default-Pakete verwendet werden, spielt es keine Rolle, ob eine Klasse vom Typ public ist, denn alle Klassen liegen in demselben Paket. Werden aber Klassen aus externen Paketen eingebunden, so gelingt dies nur, wenn die einzubindende Klasse vom Typ public ist. Andernfalls verweigert der Compiler deren Einbindung und bricht die Übersetzung mit einer Fehlermeldung ab. |