6.3 Pakete
Ein Paket ist eine Gruppe von thematisch zusammengehörigen Klassen, die sich normalerweise1 in einem Verzeichnis befinden. Den Verzeichnisnamen gibt ein Paketname an. Nehmen wir folgende Verzeichnisstruktur an:
suessigkeiten/
suessigkeiten/Zucker.java
suessigkeiten/Schokolade.java
Die Definition der Klasse Zucker enthält als oberstes eine package-Anweisung, die sie dem Paket suessigkeiten zuordnet.
package suessigkeiten;
public class Zucker
{
...
}
Das Gleiche gilt auch für die Schokolade im gleichen Paket.
package suessigkeiten;
public class Schokolade extends Zucker
{
...
}
Um Klassen innerhalb von Paketen nutzen zu können, müssen sie dem Compiler präzise beschrieben werden. Dazu gibt es zwei Möglichkeiten. Zum einen lassen sich die Klassen (oder Schnittstelle) voll qualifizieren.
suessigkeiten.Schokolade s = new süßigkeiten.Schokolade();
Eine alternative und praktischere Möglichkeit ist, dem Compiler in einer Klassendefinition mit import auf die Klassen im Paket aufmerksam gemacht.
import suessigkeiten.Schokolade;
class Weihnachtsmann
{
Schokolade s; // sonst suessigkeiten.Schokolade
}
Da die Klassen Schokolade und Zucker im gleichen Paket liegen, muss bei der Verwendung in der Vererbung die Klasse Zucker nicht extra bekannt gemacht werden.
Damit nicht alle Klassen eines Pakets einzeln aufgeführt werden müssen, lässt sich mit dem Sternchen als einer Art Wildcard auf alle sichtbaren Klassen zugreifen.
Ein Problem gibt es bei mehreren gleich benannten Klassen in verschiedenen Paketen. Hier ist eine volle Qualifizierung nötig. Ab dem SDK 1.2 gibt es im Paket java.awt und java.util eine Liste. Ein einfaches import java.awt.* und java.util.* hilft da nicht, denn der Compiler weiß nicht, ob die GUI-Komponente oder die Datenstruktur gemeint ist. Auch sagt ein import nichts darüber aus, ob die Klassen in der importierenden Datei jemals gebraucht werden. Das gleicht gilt für die Klasse Date, die einmal in java.util und einmal in java.sql zu finden ist. Lustigerweise erweitert java.sql.Date die Klasse java.util.Date. Dass der Compiler hier nicht durcheinander kommt, ist ganz einfach dadurch zu erklären, dass er die Klassen nicht nur durch ihren Namen unterscheidet, sondern viel mehr auch durch ihre Pakete. Der Compiler betrachtet intern immer eine volle Qualifizierung.
6.3.1 Hierarchische Strukturen
Pakete sind oft in Hierarchien geordnet. Dies wird auch durch die Abbildung auf die Verzeichnisstruktur des Dateisystems deutlich. Daher gehören zu einem Paket oft verschiedene Unterpakete. Es werden durch import java.* nicht automatisch alle Klassen der Unterpakete mit eingebunden. Die import-Anweisung bezieht sich nur auf ein Verzeichnis und schließt die Unterverzeichnisse nicht mit ein.
Falls eine Klasse ohne Paket-Definition implementiert wird, so befindet sie sich standardmäßig im umbenannten Paket (engl. unnamed package), oder Default-Paket. Es ist eine gute Idee, eigene Klassen immer in Paketen zu organisieren. Das erlaubt auch feinere Sichtbarkeiten.
Hier klicken, um das Bild zu Vergrößern
Abbildung 6.3 Eclipse sieht für das unbekannte Paket ein »virtuelles« Verzeichnis vor. Es nennt sich default package.
6.3.2 Paketnamen
Prinzipiell kann ein Paketname beliebig sein, doch Hierarchien bestehen in der Regel aus umgedrehten Domänennamen. Aus der Domäne zur Webseite http://javatutor.com wird also com.java-tutor. Diese Namensgebung gewährleistet, dass Klassen auch weltweit eindeutig bleiben. Ein Paketname wird in aller Regel komplett kleingeschrieben.
Die Paketnamen java, javax und sun
Sun hat für sich selbst einige Paketnamen reserviert, die von eigenen Klassen nicht genutzt werden sollen. So liegt unser java.awt.Point in einem Sun-Paket und das ist leicht durch den Teil java zu erkennen. Wenn jemand eigene Klassen in Pakete mit dem Präfix java setzen würde, etwa java.gui, der erzeugt damit Verwirrung, denn es ist nicht mehr erkennbar, ob das Paket bei jeder Distribution dabei ist - wie dies für die Sun-Klassen der Fall ist.
6.3.3 Eine Verzeichnisstruktur für eigene Projekte
Neben der Einteilung in Paketen für das eigene Programm, ist es auch sinnvoll, die gesamte Applikation in verschiedenen Verzeichnissen aufzubauen. Im Allgemeinen finden sich drei wichtige Hauptverzeichnisse: src für die Quellen, lib für externe Bibliotheken auf die das Programm aufbaut und bin (oder build) für die erzeugen Klassen-Dateien. Das Verzeichnis src lässt sich noch weiter unterteilen, etwa für Quellen, die Testfälle implementieren oder Beispiele.
src/
core/
examples/
test/
lib/
bin/
1 Ich schreibe »normalerweise«, da die Paketstruktur nicht zwingend auf Verzeichnisse abgebildet werden muss. Pakete könnten beispielsweise vom Klassenlader aus einer Datenbank gelesen werden.
|