1 von 21
Was geht in Richtung? Das Ziel Es sollen einfach wiederverwendbare Bausteine (Module) ermöglicht werden. Meist mit Unterteilung Schnittstelle und Implementierung. Die Granularität liegt über der Klassenebene. Module bestimmen die Struktur von Software. Ein Modul unterliegt folgenden Strukturierungsblickwinkeln: logisch: Welche Funktionalität (Aufgabe, Teilaspekt, Bereich) wird angeboten? physikalisch (organisatorisch): Wie werden der Code und ggf. Metainformationen abgelegt (Dateien,Verzeichnisse,Archive)? Die aktuelle Situation Im JDK gibt es aktuell kein tragfähiges Modulkonzept. Logische Strukturierung von Code ist über ein einfaches Paketkonzept möglich. Physische Strukturierung (ohne nennenswerte Metainformationen) ist per JAR-Archive machbar. OSGi ist ein verbreitetes Modulsystem außerhalb des JDK. Java 8 wird mit einem eigenen Modulsystem aufwarten. 2 von 21
Pakete 3 von 21
Dateien und Klassen Quellcode-Dateien Einfachste Form der Gruppierung: Mehrere Klassen (Quellcode) in einer Datei. Eine weitergehende Variante: Geschachtelte Klassen (s. u.). Beispiel: CircleStackLinkedListImpl, s. o. Wesentliche Randbedingungen Nur eine Klasse in einer Quellcode-Datei kann public sein, alle anderen sind "lokale" Hilfsklassen für diese "Hauptklasse". Der Name der Quellcode-Datei muß dem Namen der public-klasse entsprechen. Auf Bytecode-Ebene entsteht pro Klasse eine Datei, d. h. die "lose Klammer" auf Quellcodeebene ist hier nicht mehr sichtbar. 4 von 21
Charakteristika des Paketkonzepts In Java ist eine logische Gruppierung von Klassen zu (benamten) Paketen (package) möglich. Dies erzeugt für die Klassen eines Paketes einen eigenen Namensraum. Die logische Gruppierung impliziert eine organisatorische (physikalische) Gruppierung auf Verzeichnisebene. Die Pakete können hierarchisch strukturiert werden (betrifft Namen und Verzeichnisstruktur). Es gibt eine "benutzt"-beziehung zwischen verwendenden Klassen und verwendeten Klassen (bzw. Paketen). Für diese Zwecke existiert keine Unterteilung in Paket-Interface und -Implementierung wie z. B. in Ada, aber auch keine Header-Files in Form von Includes wie in C/C++. 5 von 21
Zuordnung von Klassen zu Paketen Vorgehensweise Die Zuordnung erfolgt durch die package-anweisung in der ersten Zeile der Quelldatei der Klasse. Fehlt die package-anweisung, gehört die Klasse zu einem Standard-Paket. Varianten 1. Einfacher Paketname // File A.java // File B.java package xyz; package xyz; public class A {...} public class B {...} 2. Hierarchischer Aufbau des Paketnamens package java.awt; public class Color {...} Namensraum Packages definieren einen eigenen Namensraum, d. h. es darf gleichnamige Klassen in anderen Paketen geben. Somit heißt die Klasse Color in Beispiel 2 genaugenommen java.awt.color (vollqualifizierter Name). Der Gültigkeitsbereich eines einfachen Klassennamens umfasst das Paket, in dem die Klasse enthalten ist. 6 von 21
Paket- und Verzeichnisstrukturen Ablage des Byte-Codes Der Byte-Code einer Klasse (class-file) muss in einem dem Paketnamen entsprechenden Unterverzeichnis liegen, wobei die Punkte durch Verzeichnistrennzeichen zu ersetzen sind. Der Compiler javac macht das automatisch. Beispiel: Die Bytecode-Datei A.class für die Klasse xyz.a muss (unter Windows) in einem Verzeichnis der Form bin\xyz abgelegt werden, wobei bin ein beliebiges Verzeichnis (bin directory) sein kann. Der Quellcode Für die Ablage des Quellcodes ist eine gleichlautende Unterverzeichnisstruktur zu empfehlen. Jedoch brauchen dabei die Oberverzeichnisse nicht identisch zu sein, sprich Sourcen und Byte-Code können in der Verzeichnisstruktur getrennt aufbewahrt werden. Praktisch wird dies durch die Option -d bin von javac ermöglicht. Eine Variante Der Byte-Code kann auch in einem Jar-Archiv mit entsprechender Verzeichnisstruktur abgelegt sein (s. u.). 7 von 21
Beispiel: Das Shape-Projekt restrukturiert 8 von 21
Laufzeitverwendung von Klassen aus Paketen Laden der Klassen Damit die entsprechenden Klassen vom Interpreter java und Compiler javac (und weiteren Tools) geladen werden können, müssen deren Oberverzeichnisse (die Verzeichnisse, ab denen die Paketstruktur beginnt) in der CLASSPATH-Umgebungsvariable stehen. Beispiel Der Pfad von bin (enthält das Verzeichnis xyz) muss explizit im Klassenpfad stehen, damit die Klassen A und B dieses Pakets verwendet werden können. Starten eines Programms Die Klasse mit der Main-Methode muss dem Interpreter mit vollqualifiziertem Klassennamen als Parameter übergeben werden. Beispiel % java shapeproj.test.shapesusage Bei Applets übernimmt die Codebase-Property die Funktion des Classpath. 9 von 21
Benutzen von Klassen aus Paketen im Quellcode Zwei Möglichkeiten Über vollqualifizierten Klassennamen java.awt.color c = java.awt.color.red; Abgekürzt mit der import-anweisung Der Namensraum des zu verwendenden Pakets kann auf verschiedene Weisen aufgeschlossen werden: import shapeproj.geom2d.shapes.circle; // genau eine Klasse import java.awt.*; // alle Klassen des Pakets import java.util; // alle Pakete und Klassen darunter... Circle circle=...; Color color=color.red; util.stack stack =...; // relativer Pfad erforderlich Das Shapes-Beispiel package shapeproj.test; import shapeproj.geom2d.point; import shapeproj.geom2d.shapes.*; import shapeproj.container.*; public class CircleStackUsage {... } 10 von 21
Konfliktmöglichkeiten bei der Benutzung Kommt eine verwendete Klasse in mehreren importierten Paketen vor, tritt ein Mehrdeutigkeitsproblem auf. Dies wird vom Compiler erkannt. Allerdings "meckert" der Compiler nur, wenn die Klasse auch verwendet wird. Es kann zur Laufzeit auch die Situation vorkommen, dass zwei unterschiedliche Class-Files für einen vollqualifizierten Klassennamen im Classpath liegen können. Es wird eine Klasse davon benutzt. Davon ausgehende Fehler sind schwer zu finden. Hilfe leisten Tools zur Verwaltung von Abhängigkeiten, z. B. Maven. 11 von 21
Statischer Import Überblick Eingeführt mit JDK 1.5 Mit import static können statische Variablen und Methoden importiert werden. Vorsicht: Der Namensraum einer Klasse wird aufgeschlossen: Übersichtlichkeit und Konflikte. Beispiel import static java.awt.color.blue; // one constant import static java.lang.math.*; // all static members import static java.lang.system.out; public class StaticImportDemo { public static void main(string[] args) { System.out.println("BLUE:" + BLUE); System.out.println("PI=" + PI); float f = 256; System.out.println("Wurzel von " + f + " : " + sqrt(f)); } } out.println("vielleicht doch besser Eclipse-Makro verwenden?"); 12 von 21
Zugriffsmodifikatoren (erweitert) Bei Member-Funktionen und -variablen Klasse selbst Subklasse Paket die Welt private x public x x x x default x x Der default-fall wird manchmal auch als friendly-situation bezeichnet (vgl. C++). Bei Klassen Nicht als public gekennzeichnete Klassen sind nur im selben Paket ansprechbar. Es dürfen prinzipiell mehrere nicht-public-klassen in einer Quellcode-Datei vorhanden sein, die einen beliebigen Namen haben kann. 13 von 21
Benutzungsabhängigkeiten (1) Abhängigkeiten zwischen Klassen Beispiel: 14 von 21
Benutzungsabhängigkeiten (2) Abhängigkeiten zwischen Paketen Beispiel: Anmerkungen Eine zyklische Verwendung zwischen Klassen kann nicht immer vermieden werden. Jedoch sollte versucht werden, die Pakete so zu strukturieren, daß keine zyklischen Abhängigkeiten zwischen Paketen entstehen. Dann können die Pakete relativ problemlos getrennt übersetzt werden. 15 von 21
Codekonsistenz In welcher Weise kann eine Inkonsistenz bei Class-Files entstehen? Was kann dies bewirken? Konsistenzerhaltung zwischen Quell- und Bytecode Isoliert für eine Klasse ist die Konsistenz vorhanden, wenn jedes Quellcode-File nach Änderung jeweils neu übersetzt wird (class-files sind neuer als java-files!). Kann durch Build-Tools gut erkannt werden (Timestamps der Dateien). Verändert sich dadurch die Schnittstelle "nach außen", müssen auch die Klassen neu übersetzt werden, die die neu übersetzte Klasse verwenden: manuell, oder automatisiert per Build-Tool (mit Spezifikation der Abhängigkeiten), Abhängigkeiten können aber dabei nicht auf die Schnittstellenänderungen beschränkt werden. Wird umgekehrt eine Klasse neu übersetzt, die eine andere Klasse referenziert und diese ist nicht "up to date" (d. h. die java-datei ist jünger als die class- Datei), so wird die referenzierte Klasse (schon vom Compiler) im selben Schritt mit übersetzt. Voraussetzung: Die Quellcode-Datei heisst so wie die referenzierte Klasse und der Quellcode ist auch mit im CLASSPATH. 16 von 21
Pakete und Namen Konvention Verwende Kleinbuchstaben und keine Sonderzeichen (außer Punkt!) Das anonyme Paket Alle Klassen die nicht explizit einem Paket zugeordnet sind, landen in dem anonymen Paket (Default-Paket ohne Namen). Eindeutige Namen Weltweit eindeutige Paketnamen erhält man durch Verwendung des eigenen Domainnamens im Paketnamen. Beispiel: package de.mycompany.departmentx... 17 von 21
Java-Archive 18 von 21
Was ist JAR? JAR ist ein Acronym für Java ARchive (vgl. tar). Es ist ein plattformunabhängies File-Format zum Ablegen von mehreren Dateien (in komprimierter Form) in einer Datei. Es basiert auf dem ZIP-Format. Es wird vor allem zum Ablegen von class-files und dort verwendeten Ressourcen (z. B. Bilder, Sound) verwendet. Dies ermöglicht ein effizientes Laden von Applikationen, falls auf diese remote zugegriffen wird (z. B. Applets). Metainformationen (z. B. Version, Ersteller) können definiert in einem JAR abgelegt werden. JARs können die gesamte Applikation oder einen Teil (Modul, Bibliothek, Framework) beinhalten. JAR-Archive können signiert werden (s. u.). In JEE gibt es als weitere etablierte (spezialisierte) Archive u. a. WAR (Web Archive) und EAR (Enterprise Archive). 19 von 21
Das jar-tool JARs können mit dem Kommandozeilentool jar erstellt, verändert, angesehen und entpackt werden (vgl. Unix tar). Beispiele (Details siehe tooldoc des jdk!) Erstellen eines Archivs jar cvf shapeproj.jar shapeproj Wirkung: Der Verzeichnisbaum unter dem Directory shapeproj wird in das neu erstellte Archiv shapeproj.jar gepackt. Inhaltsverzeichnis eines Archivs ansehen jar tvf shapeproj.jar Wirkung: Das Inhaltsverzeichnis des Archivs shapeproj.jar wird auf Stdout ausgegeben. Archiv entpacken jar xvf shapeproj.jar Wirkung: Das Archiv shapeproj.jar wird in das aktuelle Verzeichnis entpackt (evtl. notwendige Unterverzeichnisse werden erstellt). Archiv ergänzen bzw. aktualisieren jar uvf shapeproj.jar shapeproj\test\shapesusage.class Wirkung: Eine Datei (bzw. Unterverzeichnis) wird in ein Archiv eingefügt (gegebenenfalls mit Überschreiben des Inhalts). 20 von 21
Archivierte Applikationen Ausführen von archivierten Applikationen Beispiel: java -cp libdir\shapeproj.jar shapeproj.test.shapesusage Alternativ kann natürlich das JAR-File (mit Pfad) in der CLASSPATH-Variable enthalten sein. Das Manifest-File Falls nicht unterdrückt, wird bei der Erstellung eines JAR-Files eine Text-Datei META-INF/MANIFEST.MF in das Archiv eingefügt. In diese können "Header-Informationen" eingetragen werden (z. B. Versionsbezeichnungen). Beispiel: Manifest-File in shapeproj.jar Manifest-Version: 1.0 Main-Class: shapeproj.test.shapesusage Created-By: 1.6 (Sun Microsystems Inc.) Starten des Programms durch: java -jar shapeproj.jar Weitere mögliche Metainformationen Im META-INF-Verzeichnis können z. B. auch Signaturen für das JAR-File abgelegt werden. 21 von 21