Post on 14-Aug-2020
transcript
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK I – JV – 000 – 00 – TH – 08 ------------------------------------------------------------------------------------
Programmieren
in Java
Unterlagen zur Lehrveranstaltung "Programmieren in Java"
R. Thomas
(Stand : WS 2010/11)
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK I – JV – 001 – 00 – TH – 04 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel-Überblick
0. Grundkonzepte der Objektorientierten Programmierung V-JV-000 1. Einführung V-JV-100 2. Grundlegende Eigenschaften von Java V-JV-200 3. Elementare Programmfunktionalitäten V-JV-300 4. Nähere Betrachtung von Klassen und Interfaces V-JV-400 5. Graphische Benutzeroberflächen V-JV-500 6. Applets V-JV-600 7. Multithreading V-JV-700 8. Java in verteilten Systemen V-JV-800 A. Anhang : Modellierung von OOP-Programmen V-JV-A00
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK I - JV - 002 - 00 - TH – 06 -----------------------------------------------------------------------------------
Programmieren in Java
Überblick
0. Grundkonzepte der Objektorientierten Programmierung 1. Einführung 1.1. Entwicklung von Java 1.2. Nichtimplementierte C++-Eigenschaften 1.3. Schlüsselworte und Identifier 1.4. Operatoren 1.5. Wesentliche neue mit dem JDK 5.0 eingeführte Eigenschaften (Überblick) 2. Grundlegende Eigenschaften von Java 2.1. Programmiersprache und Ausführungsplattform 2.2. Klassen und Programmstruktur 2.3. Programm-Erzeugung und -Start 2.4. Packages 2.5. Standard-Bibliothek 2.6. Datentypen 2.7. Strings 2.8. Arrays 2.9. Die Klasse Object 2.10. Aufzählungstypen 2.11. Generische Programmierung 3. Elementare Programmfunktionalitäten 3.1. Zugriff zu Programmparametern 3.2. Standard-Ein- und Ausgabe 3.3. Interaktion mit dem Laufzeitsystem 3.4. Exceptions 3.5. Dateizugriff 4. Klassen und Interfaces 4.1. Definition von Klassen 4.2. Datenkomponenten 4.3. Memberfunktionen 4.4. Objekterzeugung 4.5. Konstruktoren und Initialisierungsblöcke 4.6. Vererbung 4.7. Interfaces 4.8. Eingebettete Klassen und Interfaces 4.9. Generische Klassen, Interfaces und Funktionen 5. Graphische Benutzeroberflächen 5.1. Grundprinzip 5.2. Java Foundation Classes - Überblick 5.3. Basisklassen der JFC-Hierarchie 5.4. Erstellung einer GUI-Anwendung 5.5. Beeinflussung des Erscheinungsbildes 5.6. Ausgewählte Swing-Komponenten-Klassen 5.7. Ereignisverarbeitung 6. Applets 6.1. Aufbau und Funktionsweise 6.2 Applet-Tag im HTML-Code 6.3. Java-Applet-API 6.4. Sicherheitsbeschränkungen 7. Multithreading 7.1. Erzeugung von Threads 7.2. Beenden von Threads 7.3. Synchronisation von Threads 7.4. Thread-Kommunikation über Pipes 8. Java in verteilten Systemen 8.1. Socket-basierte Kommunikation 8.2. Remote Method Invocation (RMI) A. Anhang : Modellierung von OOP-Programmen
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK I - JV - 003 - 00 - TH – 07 ------------------------------------------------------------------------------------
Programmieren in Java
Literaturhinweise
( 1) Ken Arnold, James Gosling, David Holmes The Java Programming Language (Java 5.0) Addison Wesley Publishing Company ( 2) James Gosling u.a. The Java Language specification (Java 5.0) Addison Wesley ( 3) Reinhard Schiedermeier Programmieren mit Java (Java 5.0) Pearson Studium ( 4) Y. Daniel Liang Introduction to Java Programming (Java 5.0) Pearson Prentice Hall ( 5) J. Lewis / W. Loftus Java Software Solutions (Java 5.0) Pearson Addison Wesley ( 6) Dietmar Ratz u.a. Grundkurs Programmieren in Java (Java 5.0) Band 1 und 2 Hanser-Verlag ( 7) Fritz Jobst Programmieren in Java (Java 5.0) Hanser-verlag ( 8) D.S. Malik Java Programming (Java 5.0) Course Technology, Cengage Learning ( 9) K.A. Mugal, T. Hamre, R.W. Rasmussen Java actually – A comprehensive Primer in Programming (Java 5.0) Course Technology, Cengage Learning ( 10) H.M. Deitel / P.J. Deitel Java How to Program Prentice Hall (11) H.M. Deitel / P.J. Deitel Advanced Java 2 Platform How to Program Prentice Hall (12) Guido Krüger Handbuch der Java-Programmierung Addison Wesley (13) Ian F. Darwin Java Cookbook deutsch : Java Kochbuch
O'Reilly (14) Albrecht Weinert Java für Ingenieure Fachbuchverlag Leipzig (15) Stefan Middendorf u.a. Java Programmierhandbuch und Referenz dpunkt Verlag
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 000 – 00 – TH – 01 -----------------------------------------------------------------------------------
Programmieren in JAVA
Kapitel 0
0. Grundkonzepte der Objektorientierten Programmierung 0.1. Objekte und Klassen 0.2. Kapselung 0.3. Vererbung 0.4. Polymorphie
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 001 – 00 – TH – 07 -----------------------------------------------------------------------------------
Grundkonzepte der Objektorientierten Programmierung (OOP) : Grundgedanke
•••• Grundgedanke : OOP ist eine Softwareentwicklungsmethodik, deren Grundidee aus der Simulationstechnik stammt : In dieser werden die Objekte der realen Welt sowie deren Beziehungen durch entsprechende Strukturen im Rechner abgebildet. In der OOP wird dieses Prinzip auf alle Arten von Informationen und Abläufen – auch auf solche abstrakter Natur – angewendet. Der Aufgabenbereich eines zu lösenden Problems wird in Objekte und die zwischen ihnen bestehenden Beziehungen zerlegt. Diese werden in einem das entsprechende Problem lösenden Programm nachgebildet. � Ein OOP-Programm besteht somit im wesentlichen aus einer Anzahl miteinander in Beziehung stehender Objekte. Diese Denk- und Vorgehensweise ermöglicht es, auch sehr umfangreiche und komplexe Aufgaben auf einem relativ hohem Abstraktionsniveau erfolgreich zu bearbeiten. Sie nutzt die intellektuellen Fähigkeiten, die der Mensch zur Bewältigung der ihn umgebenden Komplexität entwickelt hat, aus. Dies sind im wesentlichen die Fähigkeiten des Abstrahierens, des Klassifizierens und des Generalisierens Auf ihnen beruhen die Grundkonzepte der OOP :
◈ Bildung von Objekten ◈ Abstraktion der Objekte durch Klassen
◈ Kapselung
◈ Vererbung
◈ Polymorphie
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 011 – 01 – TH – 05 -----------------------------------------------------------------------------------
Grundkonzepte der Objektorientierten Programmierung (OOP) : Objekte und Klassen (1)
•••• Konkrete Objekte: ◇ Objekte sind in einem bestimmten Sinn abgeschlossene Einheiten, die durch zwei Aspekte gekennzeichnet sind : ▻ Sie besitzen einen (inneren) Zustand ▻ und sie verfügen über Fähigkeiten, d.h. sie können bestimmte Operationen – aktiv oder passiv – ausführen Diese Fähigkeiten und damit das dadurch bestimmte Verhalten können von außen angefordert, aktiviert werden. Die Aktivierung der Fähigkeiten kann eine Zustandsänderung bewirken. ◇ Beispiel :
•••• Objekte in der OOP ◇ In der OOP stehen Objekte im Vordergrund. Sie bilden die grundlegenden Strukturierungseinheiten eines OOP-Programmms Dabei kann ein Objekt sehr konkret aber auch beliebig abstrakt sein, es kann ein statisches Gebilde (z.B. ein Auto), oder einen dynamischen Ablauf (Vorgang) beschreiben (z.B. ein Tennisspiel). Der (innere) Zustand des Objekts wird durch Datenstrukturen (Datenkomponenten), seine Fähigkeiten – die von ihm ausführbaren Operationen – werden durch Funktionen (Prozeduren) beschrieben. Die Datenkomponenten werden auch als Attribute, die Funktionen (Memberfunktionen) als Methoden bezeichnet. ◇ Ein Objekt verbindet also Daten und die zu ihrer Bearbeitung dienenden Funktionen (Code !) zu einer Einheit. � Die von einem Objekt ausführbaren Methoden (= Funktionen) sind Bestandteil des Objekts und nur als solche relevant. Dies steht im Gegensatz zur konventionellen (prozeduralen, imperativen) Programmierung, bei der Daten und Code getrennt sind, wobei der Code (Prozeduren, Funktionen) eigenständig ist und im Vordergrund steht : Code wird auf Daten angewendet. ◇ In der OOP wird eine Methode für ein Objekt aufgerufen, in dem an das Objekt – i.a. durch ein anderes Objekt – eine entsprechende Nachricht (Botschaft) geschickt wird : Das Objekt interpretiert die Nachricht und reagiert mit der Ausführung einer zugeordneten Operation (Methode). Zwischen den Objekten bestehen also Kommunikationsbeziehungen. � Ein OOP-Programm besteht im wesentlichen aus einer Ansammlung miteinander kommunizierender und dadurch interagierender Objekte. ◇ Der OOP-Ansatz erfordert eine andere Vorgehensweise bei der Problemlösung : Statt einer Top-Down-Zerlegung des Problems (� hierarchische Modularisierung) müssen die relevanten Objekte (Aufbau und Verhalten) des Problems und die zwischen ihnen bestehenden Beziehungen ermittelt werden ( � auf- gaben- und kommunikationsorientierte Zerlegung)
Willies Uhr
Zustand : aktuelle Zeit Fähigkeiten : Uhr stellen Zeit fortschalten (ticken) Zeit darstellen
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 011 – 02 – TH – 06 -----------------------------------------------------------------------------------
Grundkonzepte der Objektorientierten Programmierung (OOP) : Objekte und Klassen (2)
•••• Klassen ◇ Der Aufbau, die Eigenschaften und Fähigkeiten von Objekten werden durch Klassen beschrieben. ◇ Eine Klasse legt die Datenkomponenten (Datenstruktur) und die Methoden zur Bearbeitung der Daten (Memberfunk- tionen) für eine Menge von gleichartigen Objekten – d.h. Objekten mit gemeinsamen Merkmalen und gleichen Fähigkeiten, die diese von anderen Objekten unterscheiden – fest. ◇ Ein spezielles Objekt der durch eine Klasse definierten Objektmenge wird auch Instanz genannt. Es unterscheidet sich von einem anderen Objekt (einer anderen Instanz) der gleichen Klasse nur durch seinen jewei- ligen Zustand, d.h. den Werten seiner Datenkomponenten. ⇒ Die Klasse entspricht dem Datentyp prozeduraler Programmiersprachen, während eine Instanz (ein spezielles Objekt dieser Klasse) einer Variablen entspricht. ◇ Eine Klasse ist mit einem Verbund-Datentyp (Structure in C, Record in Pascal) vergleichbar. Gegenüber einem nur aus Datenkomponenten bestehenden Verbund ist eine Klasse um Funktionskomponenten er- weitert. ◇ Beispiel : Klasse Uhr ◇ Jedes Objekt (Instanz) einer Klasse hat einen eigenen (inneren) Zustand � Die Datenkomponenten existieren für jedes Objekt (Unterschied zu Modulen der prozeduralen Programmierung). Sie werden erst geschaffen, wenn das Objekt generiert wird (� "Variablendefinition"). ◇ Die Methoden (Funktionen) existieren dagegen nur einmal pro Klasse. Sie sind an die Klasse gebunden. Sie werden durch die Definition der Klasse (� "Typdefinition") geschaffen. � Auch wenn es gar keine Objekte dieser Klasse gibt, existieren die Methoden. Jedes Objekt einer Klasse arbeitet mit demselben Code (� Code Sharing)
Uhr
Datenkomp : actTime Funktionskomp : setTime(...) tick() displayClock()
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 021 – 00 – TH – 08 -----------------------------------------------------------------------------------
Grundkonzepte der Objektorientierten Programmierung (OOP) : Kapselung
•••• Kapselung (Encapsulation): ◇ Der Benutzer eines Objekts (allg. : Anwenderprogramm, speziell : anderes Objekt) braucht seinen genauen Aufbau nicht zu kennen. Ihm müssen lediglich die Methoden, die er für eine Interaktion mit dem Objekt benötigt, d.h. über die er die Fähig- keiten des Objekts aktivieren und dessen Zustand verändern kann, bekannt zu sein. Von der internen Darstellung der den jeweiligen Objektzustand festlegenden Daten braucht er dagegen keinerlei Kenntnis zu haben. ◇ Nur die Funktionen (= Methoden) eines Objekts, die zu seiner Verwendung tatsächlich benötigt werden, werden allgemein zugänglich, d.h. öffentlich (public), gemacht. Sie bilden das Interface (Protokoll), über das zu dem Objekt kontrolliert zugegriffen werden kann, d.h. sie bilden seine Schnittstelle zur "Außenwelt". Die Daten (u. gegebenenfalls reine Hilfs- und Verwaltungsfunktionen) sind nur Komponenten des Objekts selbst zugänglich, d.h. privat (private). Der "Außenwelt" gegenüber bleiben sie verborgen � Sie sind nach außen gekapselt. Hierdurch wird sichergestellt, daß zu einem Objekt nur über eine wohldefinierte Schnittstelle zugegriffen werden kann.� Klassen-Schnittstelle Zugriffe zu Interna, die nur zur internen Realisierung und Verwaltung des Objekts dienen, sind nicht möglich � Vermeidung von Fehlern durch Verhinderung eines direkten und unkontrollierten Zugriffs ⇒ Trennung von Interface (Schnittstelle) und Implementierung. ◇ Die Kapselung bewirkt außerdem eine Datenabstraktion (data abstraction) : Eine Datenstruktur ist - nach außen - nicht mehr an eine bestimmte Implementierung gebunden, sondern wird allein über die auf sie anwendbaren Operationen (Methoden, Funktionen) definiert. (� abstrakter Datentyp, ADT) Eine Änderung der Implementierung - bei gleichbleibendem Interface – hat keinen Einfluß auf den Anwendungscode. ◇ Anmerkung : Manchmal wird die Kapselung als Verbergen von Informationen (information hiding) bezeichnet : Nur die Eigenschaften eines Objekts sind nach außen bekannt, die Realisierung bleibt dagegen verborgen. Streng genommen ist das für die Programmiersprache C++ nicht ganz zutreffend : Die prinzipielle Realisierung (Struktur – auch der privaten – Datenkomponenten) ist durchaus bekannt (Klassendefinition in Headerdatei), nur der Zugriff zu den internen (privaten) Daten und Funktionen ist gesperrt.
Methoden
Methoden
Daten
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 031 – 00 – TH – 06 -----------------------------------------------------------------------------------
Grundkonzepte der Objektorientierten Programmierung (OOP) : Vererbung
•••• Vererbung (Inheritance) : ◇ Weitergabe von Eigenschaften (Daten und Funktionen) eines Objekts an ein anderes Objekt. Zusätzlich zu den ererbten Eigenschaften kann ein Objekt neue spezifische Eigenschaften (Daten und Funktionen) besitzen bzw. bestimmte Eigenschaften modifizieren. � Schaffung einer neuen Art von Objekten durch Erweiterung einer bestehenden Art von Objekten. ◇ Die Vererbung führt zum Aufbau von Klassenhierarchien : Eine neue Klasse wird aus einer - oder mehreren - bereits definierten Klasse(n) abgeleitet. vorhandenene Klasse : Basisklasse, Elternklasse, Oberklasse neue Klasse : abgeleitete Klasse, Kindklasse, Unterklasse Die abgeleitete Klasse erbt die Daten und Methoden der Basisklasse(n). Dabei können geerbete Methoden abgeändert ("überschrieben") werden. Zusätzlich kann sie neue Daten und Methoden besitzen. � Abänderung und Ergänzung im Sinne einer weiteren Spezialisierung ◇ Beispiel : Ableitung der Klasse UhrMitDatum von der Klasse Uhr neue Datenkomponenten : actDate neue Funktionskomponenten : setDate(), setClock() geänderte Funktionskomponenten : tick(), displayClock()
◇ Ein Objekt einer abgeleiteteten Klasse kann immer auch als – spezielles - Objekt der Basisklasse(n) betrachtet werden : z.B. ist jede UhrMitDatum auch eine Uhr. ◇ Einfache Vererbung : Ableitung einer Klasse von nur einer Basisklasse. Mehrfachvererbung : Ableitung einer Klasse von mehreren Basisklassen (nicht von allen OOP-Sprachen unterstützt) ◇ Durch Vererbung übertragene Methoden (Funktionen) existieren nur einmal (� Code Sharing). Dies erleichtert Änderungen und Erweiterungen an bestehenden Klassenhierarchien.
Uhr
Datenkomp : actTime Funktionskomp : setTime(...) tick() displayClock()
UhrMitDatum
neue Datenkomp : actDate neue Funkt.komp : setDate(...) setClock(...)
modifiz. Funkt.komp : tick() displayClock()
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 041 – 00 – TH – 07 -----------------------------------------------------------------------------------
Grundkonzepte der Objektorientierten Programmierung (OOP) : Polymorphie
•••• Polymorphie (Polymorphism) : ◇ Verwendung des gleichen Namens für unterschiedliche - aber miteinander verwandte - Dinge. (griech. : Vielgestaltigkeit) ◇ Polymorphie in der OOP ermöglicht, daß verschiedenartige Objekte (unterschiedlicher aber von einer gemeinsamen Basisklasse abgeleiteter Klassen) unter einem gemeinsamen Oberbegriff (Basisklasse) betrachtet und bearbeitet werden können.(� Generalisierung) Beispiel : Sowohl Objekte der Klasse Uhr als auch Objekte der Klasse UhrMitDatum lassen sich als Uhr-Objekte behandeln. ◇ Für verschiedenartige Objekte werden unterschiedliche - aber meist ähnliche - Methoden mit dem gleichen Namen und gleichem Interface (gleicher Signatur) definiert (� Überschreiben von Funktionen, virtuelle Funktionen). Der gleiche Name kann damit zur Spezifizierung einer Gruppe ähnlicher - aber doch unterschiedlicher - Operationen (Methoden) verwendet werden. . � Die gleiche durch den Namen ausgedrückte Botschaft wird - an unterschiedliche Objekte gerichtet - zum Aufruf unterschiedlicher Methoden führen. Die in einem konkreten Fall ausgeführte Operation (Methode) hängt von der tatsächlichen Klasse des Objekts ab, an das die Botschaft gerichtet ist (� "Ein Interface - mehrere Methoden"). Also nicht die Botschaft, d.h. der Aufruf, bestimmt, welche Methode (Funktion) ausgeführt wird, sondern der Empfän- ger der Botschaft. Beispiel : Die Botschaft "displayClock()" an ein UhrMitDatum-Objekt gerichtet bewirkt die Ausgabe der Uhrzeit und des Datums, während sie bei einem Uhr-Objekt nur zur Ausgabe der Uhrzeit führt. ◇ Wenn die Zuordnung einer Methode zu einer Botschaft erst zur Laufzeit vorgenommen wird, spricht man von "später Bindung" ("late binding"). Die Zuordnung bereits zur Compilezeit wird mit "früher Bindung" ("early binding") bezeichnet.
⇒⇒⇒⇒ ◇ Polymorphie ermöglicht auch - nicht nur in der OOP – das Überladen von Funktionen (Methoden) und Operatoren : ▷ Überladen von Funktionen (Function Overloading) : Mehrere Funktionen, die mit verschiedenen Datentypen arbeiten, können den gleichen Namen besitzen, sofern ihre Parameterliste (Signatur) unterschiedlich ist. Durch den gleichen Namen wird auch hier eine Art Standard-Interface (das sich aber nicht auf die Parameter erstreckt) bereitgestellt, über das sich mehrere unterschiedliche aber meist miteinander verwandte Methoden aufrufen lassen. Die speziell angewandte Methode hängt hier von den beim Aufruf übergebenen Daten (Parametern) ab. ▷ Überladen von Operatoren (Operator Overloading) : Operatoren können zur Anwendung auf unterschiedliche Datentypen umdefiniert werden. Ein überladener Operator bewirkt den Aufruf einer speziellen - vom Benutzer erstellten - Funktion. � Rückführung auf Überladen von Funktionen.
Polymorphie erlaubt durch die Schaffung eines Standardinterfaces die einheitliche Verarbeitung unterschiedlicher Objekte, die über gemeinsame Grundfähigkeiten verfügen. Dadurch wird die Beherrschung einer größeren Komplexität ermöglicht.
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 100 – 00 – TH – 03 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 1
1. Einführung 1.1. Entwicklung von Java 1.2. Nichtimplementierte C/C++-Eigenschaften 1.3. Schlüsselworte und Identifier 1.4. Operatoren 1.5. Wesentliche neue mit dem JDK 5.0 eingeführte Eigenschaften (Überblick)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 111 – 00 – TH – 05 ------------------------------------------------------------------------------------
Entwicklung von Java
•••• Der Weg zu Java
► 1990 (Dez.) Patrick Naugthon, Fa SUN Microsystems, kritisiert die von seiner Fa eingesetzte und vertriebene Hard- und Software als nicht mehr zeitgemäss. Als Folge wird eine Arbeitsgruppe eingesetzt, die zukünftige Entwicklungstrends in Hard- und Software erkennen, untersuchen und realisieren sollte.� späterer Name Green Project Mitglieder waren – neben Patrick Naughton – James Gosling und Mike Sheridan Entwicklung eines Prototypen zur Steuerung und Integration von Haushaltgeräten
► 1991 (Juni) James Gosling beginnt im Rahmen des Green Projects die Arbeit an der portablen Interpretersprache Oak, die später in Java umbenannt wird
► 1992 Vorstellung des entwickelten Geräts (*7, Star Seven), das einem heutigen Palm-Computer glich. Hauptbestandteile : neben diversen Hardwarekomponenten ein Betriebssystem (Green-OS), die Interpretersprache Oak und ein Graphiksubsystem (Aspen). In der Folgezeit wird versucht, das Gerät zur Serienreife zu entwickeln (Gründung der Fa. First Person Inc) 1994 Der Versuch zur kommerziellen Verwendung von Star Seven scheitert endgültig. Einsatz der neuen Programmiersprache Oak (Java) zur Entwicklung von Applets und eines WEB-Browsers zum Herunterladen und Ausführen derselben (WebRunner, später umbenannt in HotJava) Arthur van Hoff (seit Sept. 1993 im Green Project tätig) implementiert einen Java-Compiler in Java.
► 23.5.1995 Vorstellung von Java und HotJava auf der SunWorld '95 Offizieller Geburtstag der Sprache Java. Ankündigung von Netscape, Java für den Einsatz in seinem Browser zu lizenzieren. •••• Java-Development Kits Werden von Sun als "offizielle Java-Versionen" zum Download bereitgestellt. Enthalten Compiler, Interpreter (Java Virtual Machine, JVM), weitere Dienstprogramme und Standard-Bibliothek
► 1996 (Jan.) Freigabe des Java Development Kits 1.0 (JDK 1.0)
► 1997 JDK 1.1
► 1998 JDK 1.2, kurze Zeit später umbenannt in Java 2 Platform
► 2000 JDK 1.3 (Offizieller Name : Java2 System Development Kit 1.3 ,J2SDK 1.3)
► 2002 JDK 1.4 (J2SDK 1.4)
► 2004 JDK 1.5 (JDK 5.0) ► 2006 JDK 1.6 (JDK 6.0) •••• Java2-Plattformen
► Java2 Standard Edition (J2SE)
► Java2 MicroEdition (J2ME), eingeschränkter Sprachstandard für den Einsatz in Geräten wie Mobiltelefonen, PDAs usw
► Java2 Enterprise Edition (J2EE), zusätzliche Komponenten zur Entwicklung unternehmensweiter verteilter Anwendungen (u.a. Enterprise Java Beans, EJB) •••• Wurzeln von Java
► C/C++
► Einflüsse weiterer objektorientierter Programmiersprachen wie Oberon, Ada, Eiffel, Objective-C
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 121 – 00 – TH – 05 -----------------------------------------------------------------------------------
In Java nicht implementierte C/C++-Eigenschaften •••• Syntax und Semantik von Java entsprechen weitgehend der Syntax und Semantik von C/C++. •••• Zahlreiche fehleranfällige oder redundante Bestandteile /Eigenschaften von C/C++ wurden jedoch nicht implementiert. Wo sinnvoll und erforderlich sind diese durch "bessere" Konzepte ersetzt. Im wesentlichen fehlen :
▻ Pointer und Pointerarithmetik
▻ Funktionspointer
▻ Speicherklassen (auto, register, extern)
▻ Globale Variable
▻ freie Funktionen ▻ inline-Funktionen ▻ die strukturierten Typen struct und union
▻ Bitfelder ▻ Datentyp long double ▻ vorzeichenlose Datentypen (kein unsigned und damit auch kein signed) ▻ Äquivalenz zwischen logischen (bool) und ganzzahligen Werten (keine Konvertierung zwischen bool und int)
▻ Einführung neuer Typnamen mittels typedef ▻ Sprunganweisung goto ▻ sizeof-Operator
▻ Komma-Operator
▻ Preprozessoranweisungen (Textersatz (Makros), bedingte Kompilierung)
▻ Header-Dateien
▻ Extern- und Vorwärtsreferenzen
▻ Dynamische Allokation von Variablen einfacher Datentypen ▻ Datentypen long long, _Bool, sowie komplexe und imaginäre Datentypen reine C- Eigenschaft (C99)
▻ Datentyp wchar_t (in C ein in Headerdateien ,mittels typedef definierter Typ)
▻ Statische Allokation von Objekten
▻ explizite Freigabe dynamisch allozierten Speichers (kein delete-Operator)
▻ Default-Parameter von Funktionen
▻ Destruktoren
▻ Explizites Überladen von Operatoren (Operatorfunktionen)
▻ Mehrfachvererbung
▻ Templates (ab JDK 5.0 gibt es zwar generische Datentypen und generische Methoden, die aber nicht 100%ig C++-Klassen-(und Funktions-)Templates entsprechen)
▻ Explizite Referenzen ▻ Befreundete Funktionen und Klassen (kein Schlüsselwort friend) •••• Die folgenden Eigenschaften von C/C++ wurden erst mit dem JDK 5.0 eingeführt : ▻ Aufzählungstypen (enum),
▻ Variable Parameterliste bei Funktionen
reine C++-Eigenschaften
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 131 – 00 – TH – 04 -----------------------------------------------------------------------------------
Vergleich der Schlüsselworte und Identitifier von Java, C und C++ •••• Schlüselworte (key words)
•••• Identifier
◇ Identifier (Namen) in Java werden nach den gleichen Regeln wie in C gebildet :
▻ Sie bestehen aus Buchstaben, dem Underscore ('_') und Ziffern
▻ Sie müssen mit einem Buchstaben oder dem Underscore ('_') beginnen
▻ Groß- und Klein-Buchstaben sind unterschiedlich
▻ Sie dürfen nicht wie ein reserviertes Wort (einschliesslich false, true und null) lauten
◇ Zusätzlich dürfen Java-Identifier das Dollarzeichen ('$') enthalten. Dieses wird wie ein Buchstabe behandelt (Beginn mit '$' ist zulässig)
◇ Als Buchstaben sind alle Unicode-Buchstaben (also auch andere als im lateinischen Alphabet) zulässig
◇ Java-Identifier dürfen aus beliebig vielen Zeichen bestehen.
reine C++- Schlüsselworte, die nicht in Java enthalten sind
Schlüsselworte, die in C, C++und Java enthalten sind *) in Java reserviert, aber nicht verwendet
neue Schlüsselworte von Java
**) genau genommen handelt es sich hierbei in Java nicht um ein Schlüsselwort, sondern um eine Konstante (literal)
break else return case enum short char float static const *) for switch continue goto *) void default if volatile do int while double long
abstract implements null **) assert import strictfp boolean instanceof super byte interface synchronized extends native throws final package transient finally
catch private throw class protected true **) false **) public try new this
asm friend typeid bool mutable typename const_class namespace using delete operator virtual dynamic_cast reinterpret_cast wchar_t explicit static_cast export template
auto signed typedef extern sizeof union inline struct unsigned register
restrict _Complex _Imaginary _Bool
Schlüsselworte, die die in C++und Java enthalten sind
C- u. C++- Schlüsselworte, die nicht in Java enthalten sind
reine C-Schlüssel- worte
Java
C++
C
C
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 141 – 00 – TH – 03 -----------------------------------------------------------------------------------
Operatoren von Java •••• Operator-Hierarchie von Java
Priorität Operator Operation Assoziativität 1 [] Indizierung l � r
() Funktionsaufruf . Komponentenzugriff ++ (Postfix) Increment -- (Postfix) Decrement 2 ++ (Prefix) Increment l r
-- (Prefix) Decrement + Identität - Negation (arithmetisch) ! Negation (logisch) ~ bitweises Komplement 3 new Objekterzeugung l r (type) Typkonvertierung (Cast) 4 * / % Multiplikation / Division / Modulus l � r
5 + Addition bzw Konkatenation (Strings) l � r
- Subtraktion 6 << Linkssschieben l � r
>> Rechtsschieben, Nachschieben des Vorzeichens >>> Rechtsschieben, Nachschieben von 0
7 < <= Vergleich (kleiner / kleiner gleich) l � r
> >= Vergleich (größer / größer gleich) instanceof Typprüfung 8 == != Vergleich (gleich / ungleich) l � r
9 & bitweises UND l � r
10 ^ bitweises EXOR l � r
11 | bitweises ODER l � r
12 && logisches UND l � r
13 || logisches ODER l � r
14 ?: bedingte Auswertung l r
15 = Zuweisung l r
*= /= %= Zuweisung mit Verknüpfungsoperation += -=
<<= >>= >>>= &= ^= |=
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 151 – 00 – TH – 02 ------------------------------------------------------------------------------------
Wesentliche neue mit dem JDK 5.0 eingeführte Java-Eigenschaften (Überblick)
•••• Neue Spracheigenschaften
▻ Generische Datentypen und Methoden (Generics) Sie erlauben eine von konkreten Datentypen unabhängige Implementierung von Algorithmen (ähnlich den Klassen- und Funktions-Templates von C++) Sie werden vor allem im Zusammenhang mit der Container-Bibliothek (collection framework) eingesetzt.
▻ Automatische Umwandlung zwischen einfachen Datentypen und ihren Wrapper-Klassen (Autoboxing/-unboxing) Dies ermöglicht die direkte Verwendung von Werten einfacher Datentypen in Situationen, in denen Objekte benötigt werden. ▻ Vereinfachte for-Anweisung (Enhanced for Loop, For-Each Loop) Sie ermöglicht eine einfachere Iteration über alle Elemente eines Arrays oder Containers ohne den expliziten Einsatz von Indexvariablen bzw Iteratoren.
▻ Aufzählungstypen (Typesafe Enums) Sie dienen zur Definition von typsicheren Konstanten Aufzählungstypen sind als besondere Klassen implementiert. Dadurch besitzen sie erweiterte Eigenschaften gegenüber den C/C++-Aufzählungstypen.
▻ Variable Parameterliste bei Funktionen (Varargs) Funktionen lassen sich so definieren, dass sie mit einer unterschiedlichen Anzahl von Parametern unterschiedlicher Typen aufgerufen werden können
▻ Import aller statischen Komponenten einer Klasse (Static Import) Hierdurch lassen sich statische Klassenkomponenten wesentlich einfacher verwenden (ohne Qualifikation mit dem Klassennamen)
▻ Metadaten (Metadata, Annotations) Metadaten sind zusätzliche Informationen, mit denen Java-Code versehen werden kann. Diese Informationen beein- flussen die Semantik eines Programms nicht direkt. Sie können aber von Codegeneratoren, anderen Tools und Bibliotheken ausge wertet werden und sich dadurch auf deren Arbeitsweise auswirken, was indirekt wieder Auswir- kungen auf die Semantik eines laufenden Programms haben kann.
•••• Verbesserungen an der Virtuellen Maschine Die JVM (Java Virtual Machine) wurde mit eine Reihe neuer Fähigkeiten versehen, die im wesentlichen eine Beschleu- nigung der Programmabarbeitung bewirken sollen.
•••• Ergänzungen/Neuerungen in der Java-Klassen-Bibliothek Eine Reihe von Klassen, die bereits in früheren JDK-Versionen vorhanden waren, wurden um zusätzliche Funktionali- täten erweitert. Darüberhinaus wurde die Bibliothek um zahlreiche neue Klassen und um weitere Teilbibliotheken ergänzt. Einzelheiten müssen der API-Dokumentation entnommen werden. Einige Beispiele :
▻ Formatierte Ausgabe analog zu C/C++ (Methode printf(), Klasse java.util.Formatter) ▻ Klasse zur Erleichterung der formatierten Eingabe (java.util.Scanner)
▻ Verbesserungen/Erweiterungen durch Einsatz der neuen Spracheigenschaften (vor allem Generics, Enhanced for Loop, Autoboxing/-unboxing, Enums), insbesondere in der Container-Bibliothek (Collection Framework)
▻ Bessere Unterstützung von Mulithreading und Multiprocessing (Teilbibliothek java.util.concurrency, Änderungen in der Klasse java.lang.Thread, neue Klasse java.lang.ProcessBuilder zur einfacheren Erzeugung von Kindprozessen)
▻ Überarbeitung der Teilbibliotheken zur Programmierung graphischer Benutzeroberflächen
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 200 – 00 – TH – 04 ------------------------------------------------------------------------------------
Programmieren in Java
Kapitel 2
2. Grundlegende Eigenschaften von Java 2.1. Programmiersprache und Ausführungsplattform 2.2. Klassen und Programmstruktur 2.3. Programm-Erzeugung und –Start 2.4. Packages 2.5. Standard-Bibliothek 2.6. Datentypen 2.7. Strings 2.8. Arrays und Array-Listen 2.9. Die Klasse Object
2.10. Aufzählungstypen 2.11. Generische Programmierung
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 211 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java als Programmiersprache und Ausführungsplattform (1) •••• Java ist mehr als eine Programmiersprache
◇ In einem ihrer früheren Artikel charakterisiert die Fa. SUN Java wie folgt :
◇ Einige dieser Eigenschaften werden dadurch realisiert, dass Java auch eine Plattform zur Ausführung von Java-Pro- grammen zur Verfügung stellt. � Java ist sowohl eine Programmiersprache als auch eine Ausführungsplattform.
◇ Mit Java untrennbar verbunden ist auch eine Standardbibliothek, die in ihrem Kernbereich (Java Core API) wichtige Sprachkonzepte implementiert und damit verwendbar macht. Zumindest dieser Kernbereich wird de facto als Bestandteil der Sprache betrachtet. •••• Elementare Charakteristika der Programmiersprache Java
◇ Einfachheit (simple) Java ist unter Berücksichtigung des KISS (Keep it Small and Simple) -Prinzips in massgebenden Umfang aus der Sprache C++ entwickelt worden. � Syntax und Semantik von Java weisen eine große Ähnlichkeit mit C++ auf. Wesentliche Bestandteile von Java sind damit C++-Programmierern vertraut, so dass Java für sie leicht erlernbar ist. Durch das Weglassen zahlreicher redundanter und fehleranfälliger Sprachelemente/-eigenschaften ist Java zudem schlanker, überschaubarer und leichter anwendbarer als C++. Gleichzeitig wird dadurch die Zuverlässigkeit der Sprache und der in ihr formulierten Programme erhöht. Zusätzlich sind sinnvolle Konzepte anderer objektorientierter Sprachen, die der Klarheit und Effizienz dienen, in Java integriert worden.
◇ Objektorientiertheit (object-oriented) Java ist eine rein objekttorientierte Sprache. Alle Funktionalität ist an Objekte bzw Klassen gebunden. Auch Arrays und Strings sind als Klassen implementiert. Alle Klassen sind – direkt oder indirekt – von der elementaren Basisklasse Object abgeleitet, die eine allgemeine Grundfunktionalität zur Verfügung stellt.
◇ Unterstützung verteilter Anwendungen (distributed) Java und seine Standardbibliothek stellen durch entsprechende Klassen eine effiziente High-Level-Unterstützung zur Netzwerkkommunikation zur Verfügung. Das RMI (Remote Method Invocation) API ermöglicht den Aufruf von Methoden entfernter Objekte in genau der gleichen Art und Weise wie von lokalen Objekten. Ergänzt werden diese Möglichkeiten durch die Fähigkeit des dynamischen Ladens von Klassen (und damit auch die Ausführung ihres Codes), nicht nur vom lokalen Rechner sondern auch über ein Netzwerk von entfernten Rechnern.
◇ Robustheit (robust) Java ist u.a. mit dem Ziel entworfen worden, sehr zuverlässige und robuste Software zu entwickeln. Viele – aber natürlich nicht alle – Arten von Programmierfehlern werden durch Java prinzipiell verhindert :
▻ Das Fehlen eines Preprozessors und des Überladens von Operatoren verhindert, dass tatsächlich anderer Code als im Quellprogramm formuliert, ausgeführt wird.
▻ Java ist eine streng typsichere Sprache ("strongly typed language"). Durch den Compiler und zur Laufzeit werden ausgedehnte Überprüfungen der richtigen Verwendung des Typ-Systems durchgeführt (Funktionsparameter, Casts)
▻ Das Fehlen von Pointern und Pointerarithmetik verhindert viele typische C/C++-Speicherzugriffsfehler
▻ Array- und Stringgrenzen werden beim Zugriff überprüft. Dies verhindert entsprechende Speicher-Überlauf- und Überschreibungsfehler
▻ Die in Java implementierte automatische Freigabe von dynamisch allokierten aber nicht mehr benötigten Speicher (Automatic Garbage Collection) erleichtert die Programmierung und verhindert zahlreiche mit der Speicherallokation und Speicherdeallokation zusammenhängende Fehler.
▻ Das Java-Laufzeitsystem und die Klassen der Standardbibliothek machen ausgiebigen Gebrauch vom Exception
Handling. Dies erleichtert das Erkennen und Behandeln diverser Laufzeitfehler.
Java : A simple, object-oriented, distributed, interpreted, robust, secure, architecture neutral, portable,
high-performance, multithreaded, and dynamic language
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 212 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java als Programmiersprache und Ausführungsplattform (2) •••• Elementare Charakteristika der Programmiersprache Java, Forts.
◇ Sicherheit (secure) Java stellt mehrere Sicherheitsschichten zur Verfügung, die es ermöglichen, Code aus einem a-priori unsicheren Netz- werk (wie z.B. das Internet) herunterzuladen und mit großer – wenn auch nicht 100%-iger Sicherheit – auszuführen (z.B. Applets, dynamisches Laden von Klassen). Im wesentlichen handelt es sich hierbei um :
▻ Java-Programme können weder direkt zum Speicher zugreifen (keine Pointer), noch Array- oder Stringgrenzen verletzen. Dies stellt einen wesentlichen Schutz gegen "bösartigen" Code dar.
▻ Alle Java-Klassen werden beim Laden auf Richtigkeit und Zuverlässigkeit überprüft ("byte-code verification", z.B. Überprüfung auf Stack-Über- oder Unterlauf, illegale Byte-Codes usw)
▻ Der Klassenlader sucht immer zuerst nach dem lokalen Vorhandensein einer Klasse. Dies stellt einen gewissen Schutz gegen das "Unterschieben" einer manipulierten Klasse ("class spoofing") dar
▻ Eine weitere Sicherheitsschicht stellt das "Sandkasten-Modell" ("sandbox model") dar, das unsicherem Code sicher- heitsrelevante Zugriffe verweigert. Z.B. ist Applets jeglicher Zugriff zum lokalen Dateisystem verboten. Weiterhin benötigen alle Bibliotheksklassen, die sicherheitsrelevante Operationen ausführen (z.B. Dateizugriff oder Netzwerkzugriff), ein SecurityManager-Objekt, das sie vor einem entsprechenden Zugriff um Erlaubnis fragen. Die von diesem freizugebenden Zugriffe werden durch ein Security Policy File festgelegt.
◇ Unterstützung von Multithreading (multithreaded) Java enthält Sprachmittel und Bibliotheksklassen zur einfachen Realisierung von Threads. Dadurch ist es in Java sehr leicht, Multithreaded-Anwendungen zu realisieren. •••• Elementare Charakteristika der Ausführungsplattform Java
◇ Interpretierte Programmausführung (interpreted) Der Java-Compiler erzeugt keinen Maschinencode sondern sogenannten Byte-Code, der zur Ausführung von einem Interpreter, der Java Virtuellen Maschine (Java Virtual Machine, JVM), abgearbeitet wird. Die JVM bildet die von Java zur Verfügung gestellte Ausführungsplattform. Zur Abarbeitung eines Java-Programms muß diese Ausführungs- plattform, also die JVM, gestartet werden. Dieser wird der – in einer Datei enthaltene – Byte-Code der Start-Klasse als Parameter übergeben. Die Byte-Codes der weiteren Klassen des Programm werden jeweils bei Bedarf von der JVM geladen. Der Byte-Code kann als "Machinencode" der JVM aufgefasst werden.
◇ Architektur-Neutralität und Portabilität (architecture neutral and portable) Ein Java-Programm ist auf jedem System lauffähig, das eine Java Virtuelle Maschine zur Verfügung stellt. Der vom Compiler erzeugte Byte-Code ist architektur-neutral. Er enthält keine implementierungsabhängigen Elemente. Auch die Sprache Java selbst ist vollkommen implementierungsunabhängig. U.a. legt Java die Größe der einfachen Datentypen exakt fest. Damit ist – sogar ein übersetztes – Java-Programm 100% portabel. Suns Motto für Java lautet deswegen :
◇ Dynamisches Verhalten (dynamic) Jede Java-Klasse kann zu jeder Zeit in eine laufende Virtuelle Maschine geladen werden. Eine derart dynamisch gelade- ne Klasse kann dann dynamisch instantiiert werden. Jede geladene Klasse wird durch ein Objekt der Klasse Class repräsentiert. Dies ermöglicht die Ermittlung von Informationen über eine Klasse zu Laufzeit (Reflection API)
◇ Hohe Leistungsfähigkeit (high-performance) Interpretierter Code ist zwar prinzipiell immer langsamer als direkt ausgeführter Maschinencode, Sun unternimmt aber große Anstrengungen, die JVM so effizient und schnell wie möglich zu realisieren. Heutige JVMs enthalten "just in time" Compiler (JIT), die Byte-Code vor der ersten Ausführung in Maschinen-Code übersetzen. Ergänzt wird dieses Konzept durch adaptive Entscheidungsalgorithmen, die zur Laufzeit den Code bezüglich Leistungsengpässen analysieren und wenig verwendeten Code nicht übersetzen, laufzeit-kritischen dagegen bestmöglich optimieren ("Hot Spot" JVM). Darüberhinaus kann besonders zeitkritischer Programm-Code in einer in Maschinen-Code direkt übersetzbaren Sprache formuliert, in nativen Maschinen-Code übersetzt und mittels des Java Native Interfaces (JNI) von der JVM aufgerufen werden. All diese Maßnahmen ermöglichen es, dass Java-Programme bezüglich der Ausführungsgeschwindigkeit zunehmend mit compilierten C/C++-Programmen konkurieren können.
Write Once, Run Anywhere
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 220 – 00 – TH – 02 -----------------------------------------------------------------------------------
Klassen in Java - Einführung
•••• Grundlegendes
◇ Klassen sind die elementaren Bestandteile jedes Java-Programms. Sämtlicher Code eines Java-Programms befindet sich innerhalb von Klassen. Ein Programm kann aus beliebig vielen Klassen bestehen.
◇ Eine Klasse definiert die Eigenschaften (den Aufbau) und das Verhalten (die Funktionalität) der von ihr instanzierbaren Objekte. Sie ist aus Klassenkomponenten aufgebaut. Klassenkomponenten können sein : - Datenkomponenten (Membervariable) � Variablendefinitionen Die Gesamtheit der Datenkomponenten beschreibt den Aufbau und – mit ihren jeweiligen konkreten Werten in einem Objekt – den Zustand der Objekte (� Objektvariable). - Funktionskomponenten (Memberfunktionen) � Funktionsdefinitionen Diese legen das Verhalten, die Fähigkeiten der Objekte fest (� Objektfunktionen).
◇ Eine Klasse kann auch Komponenten (sowohl Daten- als auch Funktionskomponenten) enthalten, die nicht objekt- spezifisch sind, sondern den Zustand und das Verhalten der Klasse selbst beschreiben. Sie sind durch den Modifizierer static gekennzeichnet. � statische Datenkomponenten (Klassenvariable) bzw statische Funktionskomponenten (Klassenfunktionen)
◇ Zusätzlich kann eine Klassendefinition - Konstruktoren enthalten Konstruktoren sind spezielle klassenspezifische Funktionen, die bei der Objekterzeugung aufgerufen werden. Sie tragen immer den Klassennamen und besitzen keinen Rückgabetyp (auch nicht void) Sie werden in Java nicht zu den Klassenkomponenten gerechnet. Ihre primäre Aufgabe besteht in der Initialisierung der Datenkomponenten des erzeugten Objekts. Falls eine Klassendefinition keinen Konstruktor enthält, wird vom Compiler implizit ein Default-Konstruktor bereitgestellt.
◇ Eine Klassendefinition kann noch weitere Bestandteile enthalten (s. später, Kapitel 4)
◇ Für den Zugriff zu den Klassenkomponenten als auch zu einer Klasse selbst können Zugriffsberechtigungen festgelegt werden. Dies erfolgt durch die Angabe von Zugriffs-Modifizierern. Wird kein Zugriffs-Modifizierer angegeben, so besteht Zugriff nur von innerhalb des Packages, in dem die Klasse definiert ist. Soll ein Zugriff von überall her möglich sein (öffentlicher Zugriff), so muß die Klasse bzw die entsprechende Komponente durch den vorangestellten Zugriffs-Modifizierer public gekennzeichnet werden. Für Klassenkomponenten existieren noch die Zugriffs-Modifizierer private (Zugriff nur von innerhalb der Klasse) und protected (Zugriff beschränkt auf die Klasse selbst, abgeleitete Klassen und das Package) (� Kapselung !) •••• Vereinfachte Syntax der Klassendefinition (vollständiges Syntax-Diagramm s. Kapitel 4)
◇ Einfachste Klassendefinition : class Simple
{ ;
}
◇ Ein etwas sinnvolleres Beispiel : class Uhr { private long actTime; // Datenkomponente void setTime(long time)
{ actTime = time; } long tick() // Funktionskomponenten
{ ++actTime; } void displayClock()
{ /* ... */ };
}
class Klassen-Name
;
{ Komponentendefinition
Konstruktordefinition
}
public
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 221 – 00 – TH – 02 -----------------------------------------------------------------------------------
Struktur von Java-Programmen (1)
•••• Modulkonzept
◇ Ein Java-Programm besteht nur aus Klassen.
◇ Jede Klasse muß in einer einzigen Quelldatei vollständig definiert und implementiert werden. Eine Aufteilung in Definitionsdatei (Headerdatei) und Implementierungsdatei wie in C++ existiert in Java nicht. Java-Quelldateien erhalten die Extension .java
◇ Jede Klasse ist in einer eigenen Quelldatei zu definieren. Ausnahme : eingebettete Klassen (nested classes). Der Quelldatei-Hauptname muß wie der (Haupt-)Klassenname lauten. Beispiel : Klasse Welcome � Quelldateiname : Welcome.java
◇ Eine Quelldatei ist die Übersetzungseinheit (Übersetzungs-Modul). Für jede enthaltene Klasse wird vom Compiler eine eigene Byte-Code-Datei erzeugt. Die Byte-Code-Datei für die (Haupt-)Klasse bekommt den Hauptnamen der Quellcode-Datei und die Extension .class Beispiel : Aus Welcome.java erzeugt der Compiler Welcome.class Die Hauptnamen der übrigen Byte-Code-Dateien sind aus den Namen der Haupt-Klasse und der eingebetteten Klassen zusammengesetzt. •••• Programmstruktur
◇ Ein Linken der getrennt übersetzten Module (Klassen-Dateien) zu einer – ausführbaren – Programm-Datei findet in Java nicht statt.
◇ Ein Java-Programm ist damit nicht in einer einzigen Datei zusammengefasst. Vielmehr besteht es – entsprechend den im Programm eingesetzten Klassen – aus einer oder mehreren Dateien.
◇ Eine dieser Dateien enthält die Start-Klasse des Programms.
◇ Ausgehend von der Start-Klasse werden die übrigen Klassen des Programms referiert. •••• Programmarten
◇ Es werden zwei Java-Programmarten unterschieden :
▻ Applikations-Programme
▻ Applets
◇ Applikationsprogramme "Normale" Java-Programme. Sie werden durch direkten Start der Virtuellen Maschine (JVM) ausgeführt. Hierfür ist dieser beim Start die Start-Klasse des Programms als Parameter zu übergeben
◇ Applets Diese Programme werden innerhalb eines Java-fähigen Web-Browsers (oder im Kontext eines anderen "applet viewers") ausgeführt. Ein derartiger Browser (bzw "applet viewer") enthält eine – gegebenenfalls über ein Plug-In eingebundene – JVM. Der Applet-Code befindet sich üblicherweise auf einem Server und wird durch ein <Applet>- Tag im HTML-Code einer Web-Seite referiert. Stößt der Browser beim Interpretieren des HTML-Codes auf ein derar- tiges <Applet>-Tag, startet er seine JVM. Diese lädt von der angegebenen URL den Byte-Code der Start-Klasse des Applets und führt ihn aus. Applets sind damit – i.a. kleine – Programme, die in einfacher Art und Weise über das Internet verteilt werden können. Da Applets prinzipiell unzuverlässigen Code enthalten können, unterliegt ihre Ausführung strengen Sicherheits- restriktionen. Der Start und die Ausführung eines Applets unterscheidet sich aber erheblich von Start und Ausführung eines Applikations-Programms.
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 222 – 00 – TH – 03 -----------------------------------------------------------------------------------
Struktur von Java-Programmen (2) •••• Start-Klasse eines Java-Applikations-Programms
◇ Die der JVM beim Start zu übergebene Klasse muß – neben möglicherweise beliebig vielen anderen Methoden – eine statische main()-Methode besitzen. Diese main()-Methode muß öffentlich zugänglich (public) und vom Typ void sein. Als formalen Parameter muß sie ein String-Array besitzen. Sie stellt den Startpunkt der Programmausführung dar.
◇ Beispiel für ein minimales Java-Programm :
◇ I.a. ist ein Java-Programm nicht klassenorientiert sondern objekttorientiert. D.h. im Programm werden Objekte erzeugt, die miteinander kommunizieren. Die Erzeugung des "ersten" Objekts erfolgt dann in der main()-Methode der Start-Klasse :
▻ Entweder durch Instantiierung einer anderen Klasse (Start-Klasse dient nur zum Programmstart)
▻ oder durch Instantiierung der eigenen Klasse (Start-Klasse enthält auch spezifische Programmfunktionalität)
◇ Ausgehend vom ersten Objekt werden dann die weiteren Objekte erzeugt.
◇ Beispiel für ein minimales Java-Programm mit Objekterzeugung :
◇ Anmerkung : Häufig wird auch bei Klassen, die in der späteren Verwendung nicht als Start-Klassen dienen sollen, eine statische main()-Methode vorgesehen. Diese Methode enthält dann i.a. Code, der das – weitgehend isolierte – Testen der Klasse ermöglicht.
// Welcome.java public class Welcome { public static void main(String[] args) { System.out.println("Welcome to the world of Java"); } }
// Willkommen.java public class Willkommen { Willkommen() // Konstruktor { // nur zur Demonstration } void begruessung() // Memberfunktion { System.out.println("Willkommen bei Java"); } public static void main(String[] args) { Willkommen gruss = new Willkommen(); // Erzeugung eines Objekts grus.begruessung(); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 231 – 00 – TH – 02 -----------------------------------------------------------------------------------
Erzeugung und Start von Java-Programmen •••• Vom Quellprogramm zur Programmausführung
•••• Aufruf des Java-Compilers (Kommandozeilen-Tool javac des JDK)
◇ Der Compiler sucht die zu übersetzende Quelldatei ausgehend vom aktuellen Arbeitsdirectory. Befindet sich die Datei in einem anderen Directory, ist ein entsprechender Zugriffspfad anzugeben.
◇ Der Name der zu übersetzenden Quelldatei ist einschließlich der Extension .java anzugeben.
◇ Beispiel : Quelldatei Welcome.java im Directory E:\Java\Vorl E:\Java\Vorl>javac Welcome.java
◇ Der Compiler erzeugt – bei Fehlerfreiheit – eine Byte-Code-Datei (hier : Welcome.class) im Verzeichnis der Quelldatei.
◇ Fehler werden zusammen mit der Zeilennummer und dem Quelldateinamen gemeldet.
◇ Werden in einer Quelldatei weitere Klassen referiert und findet der Compiler keine entsprechenden .class-Dateien, versucht er diese durch zusätzliches Übersetzen der entsprechenden .java-Dateien zu erzeugen. (Ausnahme : Klassen der Standardbibliothek) •••• Aufruf des Java-Interpreters (Kommandozeilen-Tool java des JDK)
◇ Dem Java-Interpreter ist der Klassenname (nicht der Dateiname, d.h. keine Extension !) der Start-Klasse als Kommandozeilenparameter zu übergeben.
◇ Der Java-Interpreter sucht nach der Byte-Code-Datei der Start-Klasse im aktuellen Directory und – falls dort nicht vorhanden – in den Directories, die in der Environment-Variablen CLASSPATH enthalten sind.
◇ Beispiel : Byte-Code-Datei Welcome.class (mit Klasse Welcome) im Verzeichnis E:\Java\Vorl CLASSPATH-Variable ist nicht gesetzt. E:\Java\Vorl>java Welcome
◇ Werden von der Start-Klasse weitere Klassen benötigt, sucht der Interpreter die entsprechenden Byte-Code-Dateien im aktuellen Directory bzw in den Directories der CLASSPATH-Variablen (Ausnahme : Klassen der Standardbibliothek)
◇ Wird eine benötigte Byte-Code-Datei nicht gefunden, wird die Exception NoClassDefFoundError erzeugt.
Quell-Datei
(z.B.Welcome.java)
Java-Compiler
Byte-Code-Datei
(z.B.Welcome.class)
Java-Interpreter (Java Virtual Machine)
weitere
Byte-Code-Dateien
javac
java
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHISCHE INFORMATIK V – JV – 232 – 01 – TH – 01 ------------------------------------------------------------------------------------
Java-Archiv-(JAR-) Dateien (1)
•••• Grundsätzliches
◇ Das JAR-Dateiformat ermöglicht die Zusammenfassung von mehreren Dateien in einer einzigen Datei (� JAR-Archiv). Es ist plattform-unabhängig und basiert auf dem ZIP-Dateiformat.
◇ Es dient im wesentlichen zur Zusammenfassung
▻ von mehreren class-Dateien in einem einzigen Bibliotheks-Archiv
▻ von den zu einer Java-Applikation (oder einem Applet) gehörenden Dateien (class-Dateien und sonstige Dateien, wie benötigte Daten-Dateien usw) zu einer einzigen Datei.
◇ Eine JAR-Datei enthält neben den zusammengefassten Dateien im allgemeinen auch Meta-Informationen über bestimmte Eigenschaften und die Verwendung des Archivs. Diese befinden sich in Dateien, die in dem bei der Archiverzeugung – automatisch – hinzugefügten Directory META-INF angelegt werden. Die wichtigste dieser Meta-Informations-Dateien ist die Manifest-Datei MANIFEST.MF. U.a. enthält diese den CLASSPATH für zu verwendende Bibliotheken (außer Standard-Bibliothek) (Eintrag Class-Path:)sowie die Startklasse bei Applikations-Archiven (Eintrag Main-Class:) Anmerkung : Die Erzeugung des Directories META-INF und der Datei MANIFEST.MF kann unterdrückt werden.
•••• Erzeugung und Manipulation von JAR-Dateien
◇ Hierfür ist im JDK das Programm jar (Java Archive Tool) enthalten
◇ Die Arbeitsweise dieses Programms wird durch Kommando-Optionen gesteuert.
◇ Überblick über einige wichtige mit dem Programm jar ausführbare Operationen : Anmerkungen : Für die in ein JAR-Archiv aufzunehmenden Dateien (input-file(s)) gilt : - Mehrere Datei-Angaben sind durch Blanks zu trennen
- Gegebenenfalls ist der jeweilige Zugriffspfad anzugeben. Insbesondere trifft dies für class-Dateien in einer Package-Struktur zu.
- Die Angabe des Wildcard-Zeichens * ist zulässig - Die Angabe von Directories ist zulässig. Es werden die Directories sowie alle Dateien, die sich in dem Directory und den darunterliegenden Directories befinden, eingebunden
◇ Beispiel : JAR-Datei PkDemo.jar soll zusammenfassen (Dateipfade beziehen sich auf das aktuelle Directory) : - Klasse vrl.pk1.PkDem1 (Datei-Pfad : vrl\pk1\PkDem1.class) - Klasse vrl.pk2.PkDemUse (Datei-Pfad : vrl\pk2\PkDemUse.class) Klasse vrl.pk2.PkDemUse ist Startklasse
�
Erzeugung einer jar-Datei jar cf jar-file input-file(s) Erzeugung einer jar-Datei für eine jar cfe jar-file startklasse input-file(s)
Java-Anwendung (gleichzeitige Festlegung der Startklasse) (Angabe des vollqualifizierten Klassennamens für die Startklasse) Update einer existierenden jar-Datei jar uf jar-file input-file(s)
(Hinzufügen weiterer Dateien, Überschreiben vorhandener Dateien) Ausgabe des Inhalts einer jar-Datei jar tf jar-file Extraktion des Inhalts einer jar-Datei jar xf jar-file
jar cfe PkDem.jar vrl.pk2.PackDemUse vrl\pk1\PkDem1.class vrl\pk2\PkDemUse.class
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHISCHE INFORMATIK V – JV – 232 – 02 – TH – 01 ------------------------------------------------------------------------------------
Java-Archiv-(JAR-) Dateien (2) •••• Start einer Java-Applikation, die sich in einer JAR-Datei befindet
◇ durch Aufruf des Java-Interpreters mit der jar-Option. Statt der Startklasse ist dem Interpreter die JAR.Datei, die die Startklasse enthält, zu übergeben. Programmparameter können – wie bei der direkten Angabe einer Startklasse – zusätzlich übergeben werden.
◇ Beispiel : Start der in PkDem.jar enthaltenen Applikation. Der Applikation ist die Datei daten.txt als Programmparameter zu übergeben �
•••• Aufnahme von CLASSPATH-Info in eine JAR-Datei
◇ Es gibt Situationen bei denen eine in einer JAR-Datei zusammengefasste Applikation (oder Applet) Klassen benötigt, die weder in der JAR-Datei enthalten noch über die aktuelle CLASSPATH-Variable zugänglich sind (Klassen in einer speziellen Bibliothek).
◇ Die für den Zugriff zu diesen Klassen notwendige – temporäre – Ergänzung des Klassenpfades kann durch Aufnahme entsprechender Informationen in die Manifest-Datei des JAR-Archivs erreicht werden.
◇ Dies wird folgendermaßen ermöglicht :
▻ Die zusätzlich benötigten Bibliotheksklassen müssen in einer oder mehreren weiteren JAR-Dateien zusammenge- fasst sein.
▻ Diese JAR-Dateien dürfen nicht in der sie benutzenden JAR-Datei enthalten sein.
▻ Erstellung einer Text-Datei, die den in die Manifest-Datei aufzunehmenden Class-Path –Header enthält : Class-Path: jar-file(s) (Angabe der Zugriffspfade, mehrere durch Leerzeichen getrennt) Diese Textdatei muss mit einem Zeilenende-Zeichen abgeschlossen sein.
▻ Bei der Erzeugung des JAR-Archivs ist zusätzlich die Option m sowie die Manifest-Text-Datei anzugeben : jar cfem jar-file startklasse manifest-text-file input-file(s)
◇ Beispiel : Im Directory AppTest sind die beiden Directories MyLib und MyApp eingetragen. Das Directory MyLib enthält die JAR-Datei MyUtil.jar. Diese fasst einige Utility-Klassen, die von mehreren Applikationen benötigt werden, zusammen. Eine dieser Applikationen wird durch die Klassen App1 und AppHelp1 gebildet. Ihre Klassendateien befinden sich im Directory MyApp in einer Directory-Struktur, die ihre Package- Struktur nachbildet : hm\ee\jvpr1\App1.class bzw hm\ee\jvpr1\AppHelp1.class. Startklasse sei die Klasse App1. Für die Applikation soll im Verzeichnis MyApp die JAR-Datei App1.jar erzeugt werden : Erzeugung der Text-Datei Manifest.txt mit dem Inhalt (im Directory MyApp) : Class-Path: ..\MyLib\MyUtil.jar Erzeugung der JAR-Datei App1.jar: �
java –jar PkDem.jar daten.txt
jar cfem App1.jar hm.ee.jvpr1.App1 Manifest.txt hm\ee\jvpr1\*.class
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 241 – 00 – TH – 02 -----------------------------------------------------------------------------------
Packages in Java (1)
•••• Packages als Namensräume
◇ Klassen lassen sich in Java in Paketen (Packages) zusammenfassen. Packages sind die Java-Entsprechung der Namensräume (name spaces) von C++.
◇ Packages haben einen Namen und können hierarchisch strukturiert (Package � Unter-Package) sein. Package-Namen können aus mehreren Bestandteilen bestehen, die durch einen Punkt (.) voneinander getrennt sind.
◇ Damit lässt sich eine Klasse über einen vollständigen (voll-qualifizierten) Klassennamen ansprechen. Dieser besteht aus dem eigentlichen Klassennamen, dem der durch einen Punkt (.) abgetrennte Package-Name vorangestellt ist. Beispiel : Klasse Date im Package java.util voll-qualifizierter Klassenname : java.util.Date
◇ Mittels Packages lassen sich Namenskonflikte, insbesondere zwischen Klassen unterschiedlicher Hersteller (Biblio- theken), weitgehend vermeiden.
◇ Empfohlene Konvention zur Vergabe von Package-Namen : Beginn des Package-Namens mit dem invertierten Internet-Domain-Namen des Herstellers. Beispiel : Fa. SESA, Internet-Domain-Name : sesa.com Package-Name : com.sesa.wmf Es ist auch üblich, aus Gründen der Übersichtlichkeit den Top-Level-Domain-Namen wegzulassen.
◇ Klassen, die explizit keinem Package zugeordnet sind, befinden sich im namenlosen Package (unnamed package). Für die Verwendung in Bibliotheken sind derartige Klassen nicht geeignet. •••• Packages als Directory-Struktur
◇ Ein strukturierter Package-Name wird in eine entsprechende Directory-Struktur abgebildet.
◇ Beispiel : Klassen-Dateien des Packages com.sesa.wmf befinden sich im Verzeichnis com\sesa\wmf
◇ Das Start-Verzeichnis einer derartigen Directory-Struktur muss sich im aktuellen Verzeichnis oder in einem über die CLASSPATH-Variable festgelegten Verzeichnis befinden.
◇ Package-Namen ermöglichen damit eine strukturierte und dadurch übersichtliche Ablage von Klassen-Dateien.
◇ Klassen-Dateien des namenlosen Package müssen direkt im aktuellen Directory bzw in einem durch die CLASSPATH- Variable festgelegten Verzeichnis liegen. •••• Package-Zuordnung einer Klasse
◇ Hierzu dient die package-Vereinbarung Beispiel : package fhm.ee.vorl;
◇ Die package-Vereinbarung muss am Beginn einer Quelldatei (erste Vereinbarung) stehen. Sie legt fest, dass die nachfolgend definierte Klasse zu dem angegebenen Package gehört.
Package-Name . Klassenname
Package-Name package ;
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 242 – 00 – TH – 03 -----------------------------------------------------------------------------------
Packages in Java (2) •••• Verwendung von Klassen des eigenen Packages
◇ Eine Klasse kann eine andere Klasse ihres eigenen Packages allein mit dem einfachen Klassennamen verwenden.
◇ Jede Klasse eines Packages hat Zugriff zu den anderen Klassen desselben Packages, die nicht private sind, auch wenn sie nicht explizit public deklariert sind. •••• Verwendung von Klassen aus anderen Packages
◇ Eine Klasse kann zu Klassen aus einem anderen Package nur zugreifen, wenn diese explizit public deklariert sind.
◇ Für die Verwendung bestehen zwei unterschiedliche Möglichkeiten :
▻ Verwendung des voll-qualifizierten Namens.
▻ Importieren der Klassen und Verwendung der einfachen Klassennamen
◇ Verwendung des voll-qualifizierten Namens : Beispiel : Verwendung der Klasse Date aus dem Package java.util Nachteil : Klassennamen können sehr lang und damit unhandlich werden. •••• Importieren von Klassen aus anderen Packages
◇ Hierzu dient die import-Deklaration. Diese existiert in zwei Formen :
▻ Importieren einer einzelnen Klasse
▻ Importieren aller Klassen eines Packages (type import on demand), aber nicht von dessen Unter-Packages
◇ Beispiel : Verwendung der Klasse Date aus dem Package java.util
◇ Anmerkung : Importieren bedeutet kein Einbinden von Code anderer Klassen.
// Datum1.java public class Datum1 { public static void main(String[] args) { java.util.Date now = new java.util.Date(); System.out.println(now); } }
voll-qualifizierter Klassenname import ;
Package-Name import . * ;
// Datum2.java import java.util.Date; // oder : import java.util.*; public class Datum2 { public static void main(String[] args) { Date now = new Date(); System.out.println(now); }
}
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 243 – 00 – TH – 02 -----------------------------------------------------------------------------------
Packages in Java (3) •••• Die Zugriffsberechtigung "package"
◇ Java kennt neben den Zugriffsberechtigungen private, protected und public die weitere Zugriffsberechtigung package.
◇ Diese Zugriffsberechtigung haben alle Klassenkomponenten einer Klasse, die nicht explizit als public, protected oder private gekennzeichnet sind. � Default-Zugriffsberechtigung
◇ Diese Zugriffsberechtigung erlaubt den Zugriff durch alle Klassen desselben Packages.
◇ Die Zugriffsberechtigung durch ein Package erstreckt sich nicht auf dessen eventuelle Unter-Packages. Klassen aus Unter-Packages haben keinen Zugriff zu package-Komponenten von Klassen ihres Ober-Packages.
◇ Anmerkung zur Zugriffsberechtigung protected : Sie umfasst in Java auch die Zugriffsberechtigung package. � Zu Klassenkomponenten mit der Zugriffsberechtigung protected können neben den abgeleiteten Klassen auch alle Klassen desselben Packages zugreifen.
◇ Beispiel :
package vorl.pack1; public class PackAccDemo { int ipa; // Zugriffsberechtigung package protected int ipo; public int ipu; // ... }
package vorl.pack1; class PackAccDemoUse1 { public static void main(String[] args) { PackAccDemo demo = new PackAccDemo(); System.out.println("PackAckDemo.ipa (package) : " + demo.ipa); System.out.println("PackAckDemo.ipu (public) : " + demo.ipu); System.out.println("PackAckDemo.ipo (protected) : " + demo.ipo); }
}
package vorl.pack1.sub; import vorl.pack1.PackAccDemo; class PackAccDemoUse2 { public static void main(String[] args) { PackAccDemo demo = new PackAccDemo(); //System.out.println("PackAckDemo.ipa (package) : " + demo.ipa); System.out.println("PackAckDemo.ipu (public) : " + demo.ipu); //System.out.println("PackAckDemo.ipo (protected) : " + demo.ipo); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 251 – 00 – TH – 04 ------------------------------------------------------------------------------------
Die Java Standard-Bibliothek (1)
•••• Allgemeines
◇ Die Java-Plattform stellt auch eine Laufzeit-Bibliothek (API) zur Verfügung.
◇ Diese sehr umfangreiche Java Standard-Bibliothek enthält zahlreiche nützliche Klassen für diverse Anwendungs- bereiche. Eine Reihe dieser Klassen implementieren wesentliche Spracheigenschaften und sind damit sehr eng mit der Sprache selbst verknüpft.
◇ Die Klassen der Standardbibibliothek sind auf verschiedene APIs aufgeteilt und in Paketen (Packages) zusammen- gefasst. Dabei ist die Zuordnung der einzelnen Klassen zu den verschiedenen Paketen nicht immer ganz stimmig, insbesondere stimmen die API-Grenzen nicht immer mit den Paketgrenzen überein.
◇ Zu vielen der Haupt-Paketen existieren Unter-Pakete.
◇ Die Pakete der im JDK enthaltenen Java Standard-Bibliothek lassen sich in drei Gruppen einteilen :
▻ Standard-Pakete. Sie gehören zu jeder Java-Plattform
▻ Standard-Erweiterungs-Pakete. Sie stellen erweiterte und ergänzende Funktionalitäten zur Verfügung und müssen nicht unbedingt auf jeder Java-Plattform zur Verfügung stehen
▻ Ergänzende Pakete von Dritt-Herstellern. Sie ergänzen und erweitern ebenfalls die Funktionalität der Bibliothek.
◇ Die Java Standard-Bibliothek ist ständig erweitert worden. (JDK 1.0 : 8 Pakete, JDK 1.4 über 130 Pakete, JDK 5.0 über 170 Pakete, JDK 6.0 203 Pakete)
◇ Sun stellt in der das JDK begleitenden Dokumentation eine ausführliche Beschreibung der Klassen zur Verfügung (Java Platform API Specification)
•••• Überblick über die Standard-Pakete
◇ Die Namen der Standard-Pakete beginnen mit java.
◇ Die folgende Tabelle gibt nur einen Überblick über die Haupt-Pakete dieser Gruppe
java.applet Applets java.awt Abstract Windowing Toolkit : Erzeugung von GUIs, mehrere Unter-Pakete java.beans Java Beans (Komponenten-Architektur von Java), ein Unter-Paket java.io Ein-/Ausgabe mittels Streams, Dateien und Serialisierung java.lang Elementare Sprachunterstützung, fünf Unter-Pakete java.math Unterstützung von Ganzzahl- und Gleitpunkt-Arithmetik java.net Unterstützung von Netzwerkanwendungen java.nio New I/O Package, verbesserter I/O-Unterstützung, ab JDK 1.4, vier Unter-Pakete java.rmi Remote Method Invocation, Entfernte Objekt-Kommunikation, vier Unter-Pakete java.security Sicherheits-Framework, vier Unter-Pakete java.sql Datenbankzugriff java.text Erweiterte Textdarstellung und –bearbeitung, Internationalisierung, ein Unter-Paket java.util Utility-Klassen, Collection Framework, spezielle Datenstrukturen, neun Unter-Pakete
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 252 – 00 – TH – 04 ------------------------------------------------------------------------------------
Die Java Standard-Bibliothek (2) •••• Überblick über die Standard-Erweiterungs-Pakete
◇ Die Namen der Standard-Erweiterungs-Pakete beginnt mit javax.
◇ Die folgende Tabelle gibt nur einen Überblick über die Haupt-Pakete dieser Gruppe (hier : Standard Edition)
•••• Ergänzende Pakete von Drittherstellern
◇ Hierzu gehören zahlreiche Pakete unterhalb der org.omg.-Hierarchie. Sie stellen im wesentlichen CORBA-Unterstützung zur Verfügung
◇ Weitere Pakete befinden sich unter den Hierachien org.w3c. und org.xml. Sie bieten Unterstützung für den Zugriff zu XML-Dateien.
◇ Das Paket org.ietf.jgss stellt ein Framework zur Nutzung von Sicherheitsdiensten (Authentifizierung, Daten- Sicherheit, Daten-Integrität usw) unterschiedlichster Mechanismen (wie z.B. Kerberos) zur Verfügung •••• Verwendung der Java Standard-Bibliothek
◇ Zur Verwendung von Komponenten der Standard-Bibliothek in eigenen Programmen werden entsprechende import- Vereinbarungen benötigt, wenn nicht voll-qualifizierte Namen verwendet werden sollen. Ausnahme : Das Paket java.lang ist so eng mit der Sprache verknüpft, dass es automatisch durch den Compiler eingebunden wird. Eine explizite import-Anweisung ist daher für Komponenten aus diesem Paket nicht erforderlich.
◇ Der Java-Compiler und der Java-Interpreter finden den Zugriffspfad zu den Bibliotheks-Dateien automatisch. Dieser muss daher nicht in die CLASSPATH-Variable aufgenommen werden (ab JDK 1.2).
javax.accessibility Unterstützung spezieller I/O-Geräte (z.B. für Braille-Zeichen) javax.activation javax.activity spezielle Exception-Klassen im Zusammenhang mit der CORBA-Serialisierung javax.annotation Unterstützung von Annotations, ein Unter-Paket javax.crypto Unterstützung kryptographischer Operationen, zwei Unter-Pakete javax.imageio I/O von Bilddateien, mehrere Unter-Pakete javax.jws Unterstützung von Web Services, ein Unter-Paket javax.lang.model Unterstützung der Modellierung der Sprache Java, drei Unter-Pakete javax.management Java Management Erweiterungen, mehrere Unter-Pakete javax.naming Zugriff zu Namensdiensten, vier Unter-Pakete javax.net Ergänzung zur Netzwerkunterstützung, ein Unter-Paket javax.print Print Service API, Zugriff zu Print Services, drei Unter-Pakete javax.rmi Ergänzung zum RMI-API, zwei Unter-Pakete javax.script Scripting API (Definition von Java Scripting Engines) javax.security Ergänzung zum Sicherheits-Framework, besteht nur aus Unter-Paketen javax.sound Sound API, besteht nur aus Unter-Paketen javax.sql Ergänzung zum Datenbankzugriffs-API (serverseitig), drei Unter-Pakete javax.swing Swing Toolkit, Erweiterungen zur GUI-Erzeugung, zahlreiche Unter-Pakete javax.tools Interfaces und Klassen für Tools zum Starten aus Programmen heraus javax.transaction Unterstützung von Transaktionen, ein Unter-Paket javax.xml Zugriff zu XML-Dateien, zahlreiche Unter-Pakete
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 261 – 00 – TH – 02 -----------------------------------------------------------------------------------
Datentypen in Java (1)
•••• Allgemeines
◇ Java ist eine streng typisierte Sprache. Das bedeutet, dass jede Variable und jeder Ausdruck einen Typ hat, der zur Compilezeit bekannt sein muß.
◇ In Java muß jede Variable immer einen definierten Wert haben. Membervariable werden automatisch mit einem Default-Wert initialisiert, sofern ihnen nicht explizit ein Wert zuge- wiesen wird. Bei lokalen Variablen verhindert der Compiler, dass sie ohne explizite Initialisierung bzw Wertzuweisung verwendet werden (Definite Assignment).
◇ In Java gibt es zwei Kategorien von Datentypen :
▻ einfache (primitive) Datentypen (primitive types)
▻ Referenz-Typen (reference types)
•••• Einfache Datentypen
◇ Variable eines einfachen Datentyps enthalten einen Wert ihres jeweiligen Typs.
◇ Java kennt acht einfache Datentypen
◇ Für jeden Datentyp ist der Wertebereich und damit die Größe des belegten Speicherplatzes eindeutig – unabhängig von der jeweiligen Plattform – festgelegt.
◇ Zu jedem primitiven Datentyp ist in der Standard-Bibliothek eine Wrapper-Klasse definiert (Package java.lang). Dies ermöglicht die Anwendung objektorientierter Prinzipien und Möglichkeiten auch auf die einfachen Datentypen.
◇ Überblick :
◇ Der Datentyp float entspricht dem 32-Bit-IEEE-Format (single precision, ANSI/IEEE Standard 754-1985) Der Datentyp double entspricht dem 64-Bit-IEEE-Format (double precision, ANSI/IEEE Standard 754-1985)
◇ Der Datentyp char zählt (zusammen mit byte, short, int und long) zu den ganzzahligen Datentypen.
◇ Die ganzzahligen Datentypen bilden zusammen mit den Gleitpunkttypen (float und double) die numerischen Typen.
◇ Der logische Datentyp boolean muß überall dort verwendet werden, wo ein logischer Operand erforderlich ist (logische Operatoren, Steuerausdrücke in den Steueranweisungen, erster Ausdruck im bedingten Auswerte-Operator). Ein Ersatz durch ganzzahlige Typen (Werte 0 und !=0) ist nicht zulässig.
Typname Größe Art des Typs Wertebereich Default-Wert Wrapper- Klasse byte 1 Byte vorzeichenbeh. ganze Zahl -128 ... +127 0 Byte short 2 Bytes vorzeichenbeh. ganze Zahl -215 ... +215-1 0 Short int 4 Bytes vorzeichenbeh. ganze Zahl -231 ... +231-1 0 Integer long 8 Bytes vorzeichenbeh. ganze Zahl -263 ... +263-1 0 Long char 2 Bytes Unicode-Zeichen alle Unicode-Zeichen '\u0000' Character float 4 Bytes Gleitpunktzahl (reelle Zahl) +/-3.4028...*1038 0.0 Float double 8 Bytes Gleitpunktzahl (reelle Zahl) +/-1.7976...*10308 0.0 Double boolean 1 Bit *) logischer Wert false, true false Boolean
*) Die belegte Speichergröße ergibt sich durch die kleinste adressierbare Speichereinheit (meist 1 Byte)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 262 – 00 – TH – 04 ------------------------------------------------------------------------------------
Datentypen in Java (2) •••• Darstellung der Werte der einfachen Datentypen (Konstante, literals)
◇ Die Wertedarstellung entspricht im wesentlichen der von C/C++
◇ Datentypen byte, short, int und long (ganzzahlige Datentypen ohne char)
▻▻▻▻ Darstellung als Dezimalzahl : Ziffernfolge aus 0 bis 9, Beginn nicht mit 0
▻▻▻▻ Darstellung als Oktalzahl : Beginn mit 0 (nur Ziffern 0 bis 7)
▻▻▻▻ Darstellung als Sedezimalzahl : Beginn mit 0x oder 0X (Ziffern 0 bis 9, a bis f, A bis F)
▻ Ziffernfolgen sind grundsätzlich (ohne Suffix) vom Typ int. Allerdings muss der durch die Ziffernfolge dargestellte Wert innerhalb des für int zulässigen Bereichs liegen.
▻ Ziffernfolgen mit dem Suffix l oder L sind vom Typ long
▻ Jede Ziffernfolge, die einen ganzzahligen Wert darstellt, kann mit dem Vorzeichen – oder + versehen werden.
◇ Datentypen float und double
▻ Exponential- oder Dezimalbruchdarstellung
▻ ohne Suffix oder mit Suffix d oder D : Datentyp double
▻ mit Suffix f oder F : Datentyp float
▻ Zusätzlich kann eine Gleitpunktzahl mit dem Vorzeichen – oder + versehen werden.
◇ Für alle numerischen Datentypen sind in den entsprechenden Wrapper-Klassen (Package java.lang) die folgenden symbolischen Konstanten (als static public) definiert : Für die Datentypen float und double sind in den Klassen Float und Double zusätzlich definiert : Verwendung dieser Konstanten immer nur zusammen mit dem jeweiligen Klassennamen (voll-qualifizierter Name) : z.B. : double dv = Double.MIN_VALUE;
◇ Datentyp char ▻ Darstellung eines Einzelzeichens in einfachen Hochkommata (single quotes), z.B.: 'A', 'Π', ':'
▻ Darstellung durch eine C-kompatible Escape-Sequenz in einfachen Hochkommata: Anmerkung : Die C-Escape-Sequenzen '\v', '\a', '\?' und '\xhhh' sind in Java nicht implementiert.
▻ Darstellung durch eine Unicode-Escape-Sequenz in einfachen Hochkommata : '\uhhhh' (h Sedezimalziffer), z.B. : '\u0041' (== 'A'), '\u00dc' (== 'Ü'), '\uffff'
NaN Not-a-Number (Repräsentation eines ungültigen Werts, z.B. 0/0) NEGATIVE_INFINITY negativ unendlich POSITIVE_INFINITY positiv unendlich
'\b' Backspace (BS) '\t' Horizontaler Tabulator (Horizontal Tab, HT) '\n' Zeilenwechsel (Newline, Linefeed, LF) '\r' Carriage Return (CR) '\f' Seitenwechsel (Form Feed, FF) '\'' Ersatzdarstellung für einfaches Hochkomma (single quote) '\"' Ersatzdarstellung für doppeltes Hochkomma (double quote) '\\' Ersatzdarstellung für Fluchtsysmbol \ '\ooo' Oktal-Escape-Sequenz, 1 bis 3 Oktalziffern, maximaler Wert : 0377
MAX_VALUE größter darstellbarer positiver Wert MIN_VALUE kleinster darstellbarer positiver Wert
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 263 – 00 – TH – 04 ------------------------------------------------------------------------------------
Datentypen in Java (3) •••• Typkonvertierungen bei einfachen Datentypen
◇ Typkonvertierungen (Casts) zwischen allen ganzzahligen Typen (einschließlich char) und den Gleitpunkt- Typen sind grundsätzlich zulässig.
◇ Implizite Typkonvertierungen bei typgemischten zweistelligen arithmetischen Operationen vor Ausführung der Operation (numeric promotion) :
▻ Nur ganzzahlige Operanden (Integer-Operation), kein Operand vom Typ long : Alle Nicht–int-Operanden werden in den Typ int umgewandelt. Die Operation wird als int-Operation ausgeführt und liefert ein int-Ergebnis
▻ Nur ganzzahlige Operanden (Integer-Operation), ein Operand vom Typ long : Der andere Operand wird in den Typ long umgewandelt. Die Operation wird als long-Operation ausgeführt und liefert ein long-Ergebnis
▻ Ein Operand ist vom Typ double. Der andere Operand wird in den Typ double umgewandelt. Die Operation wird als double-Operation ausgeführt und liefert ein double-Ergebnis
▻ Ein Operand ist vom Typ float und der andere nicht vom Typ double. Der andere Operand wird in den Typ float umgewandelt. Die Operation wird als float-Operation ausgeführt und liefert ein float-Ergebnis
◇ Implizite Typkonvertierungen zwischen numerischen Typen bei Wertzuweisungen (und Initialisierungen) : Nur zulässig, wenn sichergestellt ist, dass durch die Typkonvertierung keine Information verloren gehen kann :
▻ Ganzzahl-Werte an Ganzzahl-Variable eines größeren Typs.
▻ Ganzzahl-Werte an Gleitpunkt-Variable
▻ int-Konstante an byte-, short- oder char-Variable, wenn die int-Konstante sich auch als Wert des kleineren Datentyps darstellen lässt.
◇ Alle anderen Umwandlungen zwischen numerischen Typen, wenn also Information verloren gehen könnte, sind nur explizit möglich (Cast-Operator !).
◇ Zwischen dem Typ boolean und den numerischen Datentypen sind keinerlei Typkonvertierungen (auch nicht explizit) zulässig.
◇ Werte eines numerischen Datentyps lassen sich mit einem String-Operanden (Bibliotheks-Klasse String) mittels des Konkatenations-Operators (+) vernüpfen. In einem derartigen Fall wird der numerische Wert in seine dezimale Text-Darstellung umgewandelt und mit dem String-Operanden zu einem neuen String zusammen- gefasst. Beispiel : double dv = 74.25; System.out.println("Wert von dv : " + dv); � Ausgabe : Wert von dv : 74.25
◇ Analog lassen sich Werte des Typs boolean mit einem String-Operanden mittels des Konkatenations- Operators (+) verknüpfen. In einem derartigen Fall wird der logische Wert in seine Textdarstellung (entweder "true" oder "false") umgewandelt und mit dem String-Operanden zu einem neuen String zusammen- gefasst.
HOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 264 – 00 – TH – 03 -----------------------------------------------------------------------------------
Datentypen in Java (4)
•••• Referenz-Typen
◇ Sie referieren Objekte, d.h. Instanzen einer Klasse. Objekte können in Java nicht direkt als Werte verwendet werden (z.B. als Funktions-Parameter), sondern nur über eine Referenz.
◇ Variable eines Referenz-Typs (Referenz-Variable) werden i.a. als "Objekt-Variable" betrachtet. Tatsächlich sind es aber Pointer-Variable, die auf ein Objekt verweisen. Sie belegen nur den Speicherplatz zur Auf- nahme einer Objekt-Adresse. Ihr Wert ist also eine Speicheradresse. Bei ihrer Verwendung werden sie automatisch dereferenziert. (Anwendung des Punkt- (.) Operators zum Kompo- nentenzugriff).
◇ Eine Referenz-Variable kann immer nur auf Objekte eines bestimmten Typs bzw bestimmter Typen (Polymorphie !) zeigen. Formal werden drei Arten von Referenz-Variablen unterschieden :
▻ Klassen-Typen (sie verweisen auf Objekte der entsprechenden Klasse oder auf Objekte davon abgeleiteter Klassen)
▻ Interface-Typen (sie verweisen auf Objekte, die das jeweilige Interface implementieren)
▻ Array-Typen (sie verweisen auf Arrays, Arrays sind in Java ebenfalls – spezielle – Objekte)
◇ Objekte werden grundsätzlich nur namenlos dynamisch auf dem Heap alloziert. Hierzu dient ein new-Ausdruck (new-Operator mit nachgestellten Konstruktor-Aufruf). Konstruktoren sind spezielle klassenspezifische Funktionen, die zur Erzeugung eines Objekts benötigt werden. Sie tragen i.a. den Namen der Klasse des zu erzeugenden Objekts (Ausnahme s. Arrays). Konstruktoren können Parameter besitzen. Der new-Ausdruck liefert die Adresse des erzeugten Objekts zurück, die dann einer "Objekt-Variablen" als Wert zugewiesen werden kann. Beispiel : String sv = new String("Hallo !");
◇ Die für Referenz-Variable definierten Vergleichs-Operatoren == und != beziehen sich auf die Referenzen (Adressen) und nicht auf die referierten Objekte. Gleiche Referenzen bedeuten natürlich auch Gleichheit der referierten Objekte. Ungleiche Referenzen bedeuten aber nicht, dass auch die referierten Objekte ungleich sein müssen.
◇ Als spezielle Referenz-Konstante ist der Wert null definiert. Eine Referenz-Variable mit diesem Wert zeigt auf nichts (also auf kein Objekt). Einer lokalen Referenz-Variablen, die auf nichts zeigen soll, muss dieser Wert explizit zugewiesen werden. Beispiel : String[] sa = null; // ... sa = new String[10]; Für Referenz-Variable, die Member-Variable sind, ist null der ohne explizite Initialisierung zugewiesene Default- Wert.
◇ Da Java über eine im Hintergrund laufende automatische Garbage Collection verfügt, ist es weder notwendig noch i.a. sinnvoll und tatsächlich auch nicht möglich, dynamisch allozierten Speicher explizit freizugeben. � In Java existiert daher kein Speicherfreigabe-Operator (wie z.B. delete in C++).
◇ Mit dem auf Referenz-Variable anwendbaren Operator instanceof lässt sich überprüfen, ob das referierte Objekt von einem bestimmten Typ ist.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 265 – 00 – TH – 03 -----------------------------------------------------------------------------------
Datentypen in Java (5) •••• Anmerkungen zu den Wrapper-Klassen für die einfachen Datentypen
◇ Die Wrapper-Klassen für die einfachen Datentypen byte, short, int, long, float und double sind von der abstrakten Basisklasse Number abgeleitet :
◇ Die Klasse Number deklariert die folgenden Methoden :
▻ Rückgabe des gespeicherten (gekapselten) Wertes typgewandelt als byte-Wert
▻ Rückgabe des gespeicherten (gekapselten) Wertes typgewandelt als short-Wert
▻ Rückgabe des gespeicherten (gekapselten) Wertes typgewandelt als int-Wert
▻ Rückgabe des gespeicherten (gekapselten) Wertes typgewandelt als long-Wert
▻ Rückgabe des gespeicherten (gekapselten) Wertes typgewandelt als float-Wert
▻ Rückgabe des gespeicherten (gekapselten) Wertes typgewandelt als double-Wert Diese Methoden müssen von allen abgeleiteten Klassen jeweils implementiert werden ("Getter"-Methoden).
◇ Analog definiert die Wrapper-Klasse Character für den Datentyp char u.a. die folgenden Methode :
▻ Rückgabe des gespeicherten (gekapselten) char-Wertes
◇ Analog definiert die Wrapper-Klasse Boolean für den Datentyp boolean u.a. die folgenden Methode :
▻ Rückgabe des gespeicherten (gekapselten) boolean-Wertes
Number
Byte Short Integer Long Float Double
public byte byteValue()
public short shortValue()
public char charValue()
public boolean booleanValue()
public abstract int intValue()
public abstract long longValue()
public abstract float floatValue()
public abstract double doubleValue()
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 266 – 00 – TH – 03 ------------------------------------------------------------------------------------
Umwandlungen zwischen einfachen Java-Datentypen und ihren Wrapper-Klassen •••• Verwendung von Werten einfacher Datentypen wie Objekte
◇ Werte einfacher Datentypen und Objekte werden unterschiedlich dargestellt und referiert. Dadurch lassen sich Werte einfacher Datentypen nicht direkt in Situationen, in denen Objekte benötigt werden, verwenden (z.B. als Argument in vielen Methoden, aktueller Typ bei generischen Datentypen)
◇ Um eine derartiger Verwendung trotzdem zu ermöglichen, existieren Wrapper-Klassen für alle einfachen Datentypen. Ein Objekt einer Wrapper-Klasse kapselt einen Wert des korrespondierenden einfachen Datentyps. Dieser Wert wird bei der Objekterzeugung festgelegt (Konstruktor-Parameter) und kann später nicht mehr geändert werden.
◇ Zwischen Werten einfacher Datentypen ("primitive Werte") und den entsprechenden Objekten der jeweiligen Wrapper- Klasse sind also Umwandlungen erforderlich. •••• Explizite Umwandlung
◇ Wert ���� Objekt : Mit dem Konstruktor der korrespondierenden Wrapper-Klasse. Beispiel 1 : int iVal1 = 12; Integer iObj;
iObj = new Integer(iVal1); // Erzeugung eines neuen Integer-Objekts Beispiel 2 : Double dObj = new Double(0.75); // Erzeugung eines neuen Double-Objekts
◇ Objekt ���� Wert : Mit einer "Getter"-Methode der Wrapper-Klasse, z.B. int intValue() der Klasse Integer Beispiel 1 : int iVal2 = iObj.intValue(); // De-Wrapping Beispiel 2 : double dVal = dObj.doubleValue(); // De-Wrapping
◇ Bis einschliesslich dem JDK 1.4 mussten derartige Umwandlungen immer explizit codiert werden. •••• Implizite Umwandlung (Autoboxing/-unboxing)
◇ Mit dem JDK 5.0 eingeführt.
◇ Obige Umwandlungen müssen nicht explizit codiert werden, sie werden automatisch vom Compiler erzeugt. � Werte einfacher Datentypen und Wrapper-Objekte können völlig kompatibel zueinander verwendet werden
◇ Wert ���� Objekt (Autoboxing) : Beispiel 1 : int iVal1 = 12; Integer iObj;
iObj = iVal1; // implizite Erzeugung eines neuen Integer-Objekts Beispiel 2 : Double dObj = 0.75; // implizite Erzeugung eines neuen Double-Objekts
◇ Objekt ���� Wert (Autounboxing) : Beispiel 1 : int iVal2 = iObj; // implizites De-Wrapping Beispiel 2 : double dVal = dObj; // implizites De-Wrapping
◇ Autoboxing/-unboxing findet überall statt, wo Werte einfacher Datentypen bzw Wrapper-Objekte benötigt werden. Damit können z.B. mit Wrapper-Objekten auch "direkt" arithmetische Operationen vorgenommen werden. Beispiele : Integer iObj1 = 10;
Integer iObj2 = iObj1 + 5;
++iObj1;
◇ Autoboxing findet allerdings nur dann statt, wenn keine andere implizit mögliche Typkonvertierung anwendbar ist. Derartige Situationen können z.B. bei überladenen Funktionen auftreten. Beispiel : void func(double dv); void func(Integer io);
. . .
func(5) führt zum Aufruf der ersten Methode (func(5.0)) (int ���� double)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 271 – 00 – TH – 05 ------------------------------------------------------------------------------------
Strings in Java - Allgemeines
•••• Darstellung von Strings
◇ Strings in Java bestehen aus Unicode-Zeichen. Wie in C++ besteht eine String-Konstante (string literal) aus einer Folge von 0 oder mehr Zeichen, die in doppelte Hochkommata (double qoutes) eingeschlossen sein müssen. Die Zeichen können auch durch Escape-Sequenzen dargestellt werden. Beispiele : "\n\"Hallo\"" "\u00ea\u0256"
◇ Strings sind in Java Objekte. String-Konstante werden durch Objekte der Bibliotheks-Klasse String dargestellt. Der Inhalt derartiger Objekte ist unveränderlich. Zur Darstellung von veränderlichen Strings dienen die Bibliotheks-Klassen StringBuffer (thread-sicher) und StringBuilder (ab JDK 5.0, nicht thread-sicher, aber schneller, da keine Synchronisation erforderlich).
◇ Eine String-Variable ist – wie alle Objekt-Variablen in Java – eine Referenz-Variable. Sie enthält eine Referenz auf ein String- (bzw StringBuffer- bzw StringBuilder-) Objekt. Eine Zuweisung eines neuen Strings an eine String-Variable ("Variable vom Typ String") bedeutet nicht, dass das referierte String-Objekt geändert wird, sondern dass die String-Variable ein anderes String-Objekt referiert. Beispiel : String str = "Hausboot"; // ... str = "Segelyacht"; // str zeigt auf ein anderes Objekt ! •••• Direkte Sprachunterstützung für Strings
◇ In der Sprache Java selbst sind einige Mechanismen zur Erzeugung und Verwendung von Strings implementiert, die im Zusammenhang mit der Klasse String zur Anwendung kommen
◇ Beim Auftritt einer String-Konstanten im Quelltext erzeugt der Compiler ein String-Objekt, das mit der String- Konstanten initialisiert wird. Beispiele : System.out.println("Schoene Gruesse !"); Der Compiler erzeugt ein String-Objekt mit dem Inhalt "Schoene Gruesse !" und übergibt eine Referenz (Adresse) auf dieses Objekt der Methode println(...) String s1 = "Das alte Europa"; Der Compiler erzeugt ein String-Objekt mit dem Inhalt " Das alte Europa" und weist der Variablen s1 eine Referenz (Adresse) auf dieses Objekt zu
◇ Für String-Objekte ist der Operator + überladen als Konkatenations-Operator. Er erzeugt ein neues String-Objekt, das aus den beiden Operanden zusammengesetzt ist. Beispiel : s1 = s1 + " hatte Recht !";
◇ Der + -Operator wirkt auch dann als Konkatenations-Operator, wenn nur ein Operand vom Typ String ist. In einem derartigen Fall wird der andere Operand implizit in ein String-Objekt umgewandelt und mit dem String-Operanden zu einem neuen String-Objekt konkateniert. Die implizite Konvertierung in ein String-Objekt (string conversion) findet für jeden einfachen Typ und für jeden Referenz-Typ (Klasse !) statt. Ist die in einer Objekt-Variablen gespeicherte Referenz gleich null, wird der String "null" erzeugt. Beispiel : System.out.println("Heute ist : " + new java.util.Date()); Ein neu erzeugtes namenloses Date-Objekt (Package java.util) wird in ein String-Objekt (das das Datum als Text enthält) umgewandelt und mit dem String-Objekt "Heute ist : " zu einem neuen String-Objekt zusammengefasst. Eine Referenz auf dieses Objekt wird der Methode println(...) als Parameter übergeben.
◇ Eine String-Konkatenation kann auch mit dem += -Operator realisiert werden. Wenn hier der rechte Operand kein String-Objekt ist, wird er implizit in ein solches konvertiert.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 272 – 00 – TH – 02 -----------------------------------------------------------------------------------
Die Klasse String in Java (1)
•••• Allgemeines zur Klasse String
◇ Standard-Klasse zur Darstellung von nicht veränderlichen Strings. ◇ Bestandteil des Package java.lang
◇ Von der Klasse String können keine anderen Klassen abgeleitet werden (Die Klasse ist final)
◇ Die Klasse String implementiert das Interface CharSequence
◇ Die Klasse String enthält zahlreiche Methoden zur Verwendung von Strings, u.a. - zur expliziten Erzeugung von String-Objekten (Konstruktoren), - zur Ermittlung der Stringlänge - zum lesenden Zugriff zu String-Elementen, - zum String-Vergleich - zum Suchen in Strings - zur Extraktion von Teilstrings, - zum Kopieren von Strings mit Umwandlung aller Buchstaben in Großbuchstaben bzw Kleinbuchstaben. •••• Konstruktoren der Klasse String (Auswahl)
◇ Hinweis : Die explizite Erzeugung eines String-Objekts bei Initialisierung mit einer String-Konstanten ist ineffizient . String str = new String("Wer rastet, der rostet"); Dies führt zunächst zur impliziten Erzeugung eines String-Objektes das mit der String-Konstanten "Wer rastet, der rostet" initialisiert ist. Anschliessend wird zur expliziten Erzeugung eines weiteren String-Objekts der Copy-Konstruktor aufgerufen, dem eine Referenz auf das zuerst erzeugte Objekt übergeben wird. Eine Referenz auf das explizit erzeugte zweite Objekt wird dann der String-Variablen str zugewiesen. Vorzuziehen ist daher die direkte "Initialisierung" einer String-Variablen mit einer String- Konstanten. In diesem Fall wird nur ein String-Objekt – implizit – erzeugt String str = "Wer rastet, der rostet"; Entsprechendes gilt für die Wertzuweisung an String-Variable.
public String() Erzeugt ein String-Objekt, das den Leerstring enthält public String(String str) Erzeugt ein String-Objekt, das eine Kopie des Inhalts von str enthält (Copy-Konstruktor) public String(char[] acs) Erzeugt ein String-Objekt, das die Zeichenfolge aus acs enthält. Die Zeichen werden in das neu erzeugte Objekt kopiert. public String(byte[] abs) Erzeugt ein String-Objekt, das mit der Zeichenfolge, die durch Decodierung der byte-Werte von abs entsteht, initialisiert ist. Die Decodierung erfolgt für den Default-Zeichensatz der Implementierung public String(StringBuffer buf) Erzeugt ein String-Objekt, das mit der in buf enthal- tenen Zeichenfolge initialisiert ist. Die Zeichen werden in das neu erzeugte Objekt kopiert. public String(StringBuilder bld) Erzeugt ein String-Objekt, das mit der in bld enthal- tenen Zeichenfolge initialisiert ist. Die Zeichen werden in das neu erzeugte Objekt kopiert.
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 273 – 01 – TH – 05 -----------------------------------------------------------------------------------
Die Klasse String in Java (2) •••• Memberfunktionen Klasse String (Auswahl)
◇
▻ Gibt die Länge eines String-Objekts (= die Anzahl der enthaltenen Unicode-Zeichen) als Funktionswert zurück
◇
▻ Liefert das Zeichen mit dem Index index als Funktionswert zurück.
▻ Der zulässige Indexbereich reicht von 0 (erstes Zeichen) bis length()-1 (letztes Zeichen).
▻ Erzeugung einer IndexOutOfBoundsException, wenn ein unzulässiger Index übergeben wird.
◇
▻ Überprüfung, ob die Zeichenfolge s (z.B. Inhalt eines String-Objekts) im aktuellen Objket enthalten ist
▻ Falls ja, wird true als Funktionswert zurückgegeben, andernfalls false
◇
▻ Rückgabe des Index des ersten Auftritts des – als int-Wert übergebenen – Zeichens ch als Funktionswert.
▻ Falls das Zeichen ch nicht enthalten ist, wird der Wert –1 zurückgegeben.
▻ Beispiel : "hamburger".indexOf('r') liefert 5
◇
▻ Funktionalität wie int indexOf(int ch), allerdings beginnt die Suche am Index from
▻ Beispiel : "hamburger".indexOf('r', 6) liefert 8
◇
▻ Rückgabe des Index des ersten Auftritts des Teilstrings str.
▻ Der zurückgegebene Funktionswert ist der Index des ersten Zeichens des gefundenen Teilstrings.
▻ Falls der Teilstring str nicht enthalten ist, wird der Wert –1 zurückgegeben.
◇
▻ Funktionalität wie int indexOf(String str), allerdings beginnt die Suche am Index from
◇
▻ Ähnlich wie die Funktionen indexOf(...).
▻ Nur Ermittlung des Index des letzten Auftritts des Zeichens ch bzw des Teilsstrings str.
▻ Beispiel : "hamburger".lastIndexOf("rindfleisch") liefert -1
public int length()
public char charAt(int index)
public int indexOf(int ch)
public int indexOf(int ch, int from)
public int indexOf(String str)
public int indexOf(String str, int from)
public int lastIndexOf(int ch) public int lastIndexOf(int ch, int from) public int lastIndexOf(String str) public int lastIndexOf(String str, int from)
public boolean contains(CharSequence s) // ab dem JDK 5.0 vorhanden
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 273 – 02 – TH – 04 -----------------------------------------------------------------------------------
Die Klasse String in Java (3) •••• Memberfunktionen Klasse String (Auswahl), Forts.
◇
▻ Überprüfung, ob das übergebene Objekt ein String-Objekt ist und gleiche Länge und gleichen Inhalt wie das aktuelle Objekt hat.
▻ Falls ja, wird true als Funktionswert zurückgegeben, andernfalls false
◇
▻ Durchführung eines lexikographischen Vergleichs zwischen dem aktuellen String-Objekt und dem String- Objekt str
▻ Der Vergleich wird mit den Codewerten der einzelnen Zeichen bzw der Stringlänge ausgeführt
▻ Funktionswert : - 0, wenn beide String-Objekte gleich sind - <0, wenn das aktuelle Objekt "kleiner" als str ist - >0, wenn das aktuelle Objekt "größer" als str ist
▻ Beispiel : "haben".compareTo("hat") liefert –18
◇
▻ Überprüfung, ob das aktuelle Objekt mit dem String prefix beginnt.
▻ Falls ja, wird true als Funktionswert zurückgegeben, andernfalls false
◇
▻ Rückgabe des Teilstrings, der am Index beg beginnt und am Index end-1 endet, als neues String-Objekt (genauer : als Referenz auf ein neu erzeugtes String-Objekt mit dem entsprechenden Inhalt des Teilstrings).
▻ Erzeugung einer IndexOutOfBoundsException, falls wenigstens einer der übergebenen Indizees unzulässig ist oder beg>end ist.
▻ Beispiel : "hamburger".substring(4,8) liefert "urge"
◇
▻ Rückgabe eines neuen String-Objekts, in dem alle Buchstaben in Großbuchstaben konvertiert sind
◇
▻ Rückgabe eines neuen String-Objekts, das aus dem aktuellen Objekt durch Ersatz aller Auftritte des Zeichens alt durch das Zeichen neu und der Übernahme alle übrigen Zeichen entsteht.
▻ Ist das Zeichen alt überhaupt nicht im aktuellen Objekt enthalten, wird kein neues Objekt erzeugt, sondern das aktuelle Objekt zurückgegeben.
◇
▻ Rückgabe einer neu erzeugten Kopie des aktuellen Objekts, bei der alle führenden und endenden Blanks sowie ASCII-Steuerzeichen (Zeichencode <= '0u0020') entfernt sind
▻ Falls sowohl das erste als auch das letzte Zeichen des aktuellen String-Objekts einen Zeichencode > '0u0020' besitzen, wird keine Kopie erzeugt, sondern das aktuelle Objekt zurückgegeben
public String substring(int beg, int end)
public String toUpperCase()
public String replace(char alt, char neu)
public String trim()
public boolean equals(Object obj)
public int compareTo(String str)
public boolean startsWith(String prefix)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 274 – 00 – TH – 02 -----------------------------------------------------------------------------------
Die Klasse String in Java (4) •••• Explizite Umwandlung in eine String-Darstellung
◇ In der Klasse String existiert eine mehrfach überladene statische Memberfunktion zur Umwandlung von belie- bigen Werten der einfachen Datentypen sowie von Objekten beliebiger Klassen in eine String-Darstellung : Beispiel für die Umwandlung von double-Werten :
◇ Für jede Klasse ist in Java die folgende Memberfunktion definiert, mit der ein Objekt der jeweiligen Klasse in ein String-Objekt (textuelle Repräsentation des Objekts !) umgewandelt wird :
•••• Demonstrationsbeispiel zur Klasse String Ausgabe des Programms
// StringDemo.java public class StringDemo { public static void main(String[] args) { System.out.println("Heute ist : " + new java.util.Date()); String str = "Aller Anfang"; str = str + " ist"; str += " schwer"; System.out.println(str); int len = str.length(); System.out.println("Laenge des Strings : " + len); int idx = 6; System.out.println(idx+1 + ". Zeichen : " + str.charAt(idx)); System.out.println("Index von \"ist\" : " + str.indexOf("ist")); char ch = 'r'; System.out.println("letzter Index von " + ch + " : " + str.lastIndexOf(ch)); int ie = idx+6; System.out.print("Teilstring (" + idx + ',' + ie + ") : "); System.out.println(str.substring(idx, ie)); System.out.println(str.toUpperCase()); if (str.equals("Aller Anfang ist schwer")) System.out.println("Strings sind gleich !"); else System.out.println("Strings sind ungleich !"); int diff = "haben".compareTo("hat"); System.out.println("Vergleich von \"haben\" und \"hat\" liefert : "+diff); } }
Heute ist : Thu Sep 04 10:38:41 CEST 2003 Aller Anfang ist schwer Laenge des Strings : 23 7. Zeichen : A Index von "ist" : 13 letzter Index von r : 22 Teilstring (6,12) : Anfang ALLER ANFANG IST SCHWER Strings sind gleich ! Vergleich von "haben" und "hat" liefert : -18
public static String valueOf(double d)
public String toString()
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 275 – 00 – TH – 07 ------------------------------------------------------------------------------------
Die Klasse StringBuffer in Java (1) •••• Allgemeines zur Klasse StringBuffer
◇ Thread-sichere Klasse zur Darstellung veränderlicher Strings. Die in Objekten dieser Klasse abgelegte Zeichenfolge kann sowohl bezüglich des Inhalts als auch hinsichtlich der Länge modifiziert werden.
◇ Bestandteil des Package java.lang
◇ Die Größe des in einem StringBuffer-Objekt vorhandenen Zeichen-Puffers wird als Kapazität bezeichnet. Die Länge des enthaltenen Strings kann kleiner als die Kapazität sein. Übersteigt bei einer String-Verlängerung die neue Länge die Kapazität, wird automatisch ein neuer Puffer ausreichender Kapazität allokiert. Die Kapaziät kann auch explizit vergrößert (nicht jedoch verkleinert) werden.
◇ Viele der Memberfunktionen der Klasse String existieren auch für die Klasse StringBuffer. Zusätzlich sind zahlreiche Memberfunktionen zur String-Manipulation implementiert.
◇ Die Klassen String und StringBuffer sind nicht voneinander abgeleitet. Beide implementieren aber das Interface CharSequence. Die Klasse StringBuffer implementiert darüberhinaus das Interface Appendable.
◇ Die Klasse StringBuffer ist nicht ableitbar (Die Klasse ist final). •••• Konstruktoren der Klasse StringBuffer
•••• Memberfunktionen zur Ermittlung und Änderung der Länge und Kapazität
◇
▻ Gibt die Länge des im StringBuffer-Objekt enthaltenen Strings als Funktionswert zurück
◇
▻ Gibt die Kapazität des StringBuffer-Objekts als Funktionswert zurück
◇
▻ Setzen der Länge des im StringBuffer-Objekt enthaltenen Strings
▻ Falls neulen < akt. Stringlänge ist, wird der String entsprechend verkürzt (Kapazität bleibt gleich)
▻ Falls neulen > akt. Stringlänge ist, wird der String mit '\u0000'-Zeichen verlängert
▻ Erzeugung einer IndexOutOfBoundsException, wenn neulen<0 ist
◇
▻ Sicherstellung, dass die Kapazität >= neucap ist (Kapazitätsverkleinerung nicht möglich)
public int length()
public int capacity()
public StringBuffer() Erzeugt ein leeres StringBuffer-Objekt mit Kapazität von 16
public StringBuffer(int cap) Erzeugt ein leeres StringBuffer-Objekt, mit Kapazität = cap
public StringBuffer(String str) Erzeugt ein StringBuffer-Objekt, das mit dem Inhalt von str initialisiert ist, mit Kapazität = 16 + str.length()
public StringBuffer(CharSequence seq) Erzeugt ein StringBuffer-Objekt, das mit den in seq enthal- tenen Zeichen initialisiert ist, (ab JDK 5.0) mit Kapazität = 16 + Anzahl Zeichen in seq
public void setLength(int neulen)
public void ensureCapacity(int neucap)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 276 – 00 – TH – 05 ------------------------------------------------------------------------------------
Die Klasse StringBuffer in Java (2) •••• Anmerkungen zu den Memberfunktionen zur String-Modifikation
◇
▻ Das Zeichen an der Position idx wird gleich dem Zeichen ch gesetzt.
▻ Erzeugung einer IndexOutOfBoundsException, wenn ein unzulässiger Index (idx<0 oder idx>=length()) übergeben wird.
◇
▻ Der durch beg (erster Index) und end (letzter Index +1) festgelegte Teilstring wird durch str ersetzt.
▻ Erzeugung einer StringIndexOutOfBoundsException, wenn ein unzulässiger Index (beg<0 oder beg>length() oder beg>end) übergeben wird.
▻ Funktionswert ist eine Referenz auf das aktuelle StringBuffer-Objekt
◇
▻ Entfernen des Zeichens an der Position idx (Verkürzung der Stringlänge um 1)
▻ Erzeugung einer StringIndexOutOfBoundsException, wenn eine unzulässige Position (idx<0 oder idx>=length()) übergeben wird.
▻ Funktionswert ist eine Referenz auf das aktuelle StringBuffer-Objekt
◇
▻ Entfernen des durch beg (erster Index) und end (letzter Index +1) festgelegten Teilstrings
▻ Erzeugung einer StringIndexOutOfBoundsException, wenn ein unzulässiger Index (beg<0 oder beg>length() oder beg>end) übergeben wird.
▻ Funktionswert ist eine Referenz auf das aktuelle StringBuffer-Objekt
◇
▻ Umkehrung der Zeichen-Reihenfolge des im StringBuffer-Objekt enthaltenen Strings
▻ Funktionswert ist eine Referenz auf das aktuelle StringBuffer-Objekt
◇ Die meist verwendetsten Memberfunktionen zur String-Modifikation sind :
▻ Beide Funktionen sind für unterschiedliche Parametertypen vielfach überladen.
▻ Sie wandeln den jeweiligen Parameter in seine String-Darstellung um und - hängen dann diesen String an das aktuelle Objekt an ( append() ) bzw - fügen ihn an der angegebenen Stelle pos ein ( insert() ).
▻ Als Funktionswert geben diese Funktionen eine Referenz auf das aktuelle Objekt zurück
▻ Bei Übergabe einer unzulässigen Position (pos<0 oder pos>=length()) erzeugen die insert()- Funktionen eine IndexOutOfBoundsException
▻ Beispiel : StringBuffer strb = new StringBuffer("Ergebnis : "); int i = 0x7c; strb.append(i); // Inhalt von strb : "Ergebnis : 124"
public void setCharAt(int idx, char ch)
public StringBuffer replace(int beg, int end, String str)
public StringBuffer deleteCharAt(int idx)
public StringBuffer delete(int beg, int end)
public StringBuffer reverse()
public StringBuffer append(...) public StringBuffer insert(int pos, ...)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 277 – 00 – TH – 04 ------------------------------------------------------------------------------------
Die Klasse StringBuffer in Java (3) •••• Erzeugung eines String-Objekts aus einem StringBuffer-Objekt
◇ Mittels der StringBuffer-Memberfunktion :
▻ Sie erzeugt ein neues String-Objekt, dass mit der aktuell im aktuellen StringBuffer-Objekt enthaltenen Zeichenfolge initialisiert ist und gibt eine Referenz auf dieses als Funktionswert zurück.
▻ Dieses String-Objekt ist die String-Repräsentation des StringBuffer-Objekts
▻ Beispiel : StringBuffer strb = new StringBuffer(); // ... Manipulation von strb String str1 = strb.toString();
◇ Mittels des String-Konstruktors :
▻ Beispiel : // ... String str2 = new String(strb);
◇ Mittels der statischen String-Memberfunktion :
▻ Dieser Funktion ist das StringBuffer-Objekt als Parameter zu übergeben.
▻ Sie erzeugt ein neues String-Objekt, dass mit der aktuell im übergebenen StringBuffer-Objekt enthaltenen Zeichenfolge initialisiert ist und gibt eine Referenz auf dieses als Funktionswert zurück.
▻ Beispiel : // ... String str3 = String.valueOf(strb);
•••• Verwendung der Klasse StringBuffer durch den Compiler
◇ Der Compiler realisiert eine mehrfache String-Konkatenation unter Verwendung eines temporären StringBuffer- Objekts. Beispiel : String s1 = "Morgenstund"; String s2; s2 = '<' + s1 + '>'; Der Ausdruck s2 = '<' + s1 + '>' wird vom Compiler umgesetzt in : s2 = new StringBuffer().append('<').append(s1).append('>').toString() Hier wird nur ein temporär benötigtes StringBuffer-Objekt erzeugt. Da sein Inhalt veränderlich ist, können die zu konkatenierenden Strings bzw Stringrepräsentationen angehängt werden. Eine explizite Erzeugung von String- Objekten für die Nicht-String-Operanden ist nicht erforderlich.
◇ Ohne das temporäre StringBuffer-Objekt müsste für jede Stringrepräsentation eines Nicht-String-Operanden ein neues String-Objekt erzeugt werden. Ausserdem würde nach jedem Zwischenschritt (jeder ausgeführten Konkatenation) zusätzlich ein weiteres String-Objekt erzeugt werden. Diese zusätzlichen String-Objekte werden nach Abschluß der Gesamtoperation nicht mehr benötigt. � unnötige Speicherallokationen (und danach wieder durchgeführte Speicherfreigaben). Im obigen Beispiel würden erzeugt werden : "<", "<Morgenstund", ">" und "<Morgenstund>". Nur das letzte String-Objekt wird letzten Endes benötigt.
public String toString()
public String(StringBuffer buf)
public static String valueOf(Object obj)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 278 – 00 – TH – 03 ------------------------------------------------------------------------------------
Die Klasse StringBuilder in Java •••• Allgemeines zur Klasse StringBuilder
◇ Ab dem JDK 5.0 vorhandene alternative Klasse zur Darstellung veränderlicher Strings. Auch die in Objekten dieser Klasse abgelegte Zeichenfolge kann sowohl bezüglich des Inhalts als auch hinsicht- lich der Länge modifiziert werden.
◇ Bestandteil des Package java.lang
◇ Die Klasse StringBuilder stellt prinzipiell die gleiche Funktionalität bei im wesentlichen gleichem Methoden- Interface wie die Klasse StringBuffer zur Verfügung.
◇ Der wesentliche Unterschied zwischen den beiden Klassen besteht darin, dass StringBuffer thread-sicher ist, während dies für StringBuilder nicht zutrifft. Andererseits arbeiten die Methoden der Klasse StringBuilder schneller, da in ihnen auf die für eine Thread- Sicherheit notwendige Synchronisation verzichtet werden kann. Wenn sichergestellt ist, dass der veränderliche String nur in einem Thread verwendet werden wird, sollte der Klasse StringBuilder der Vorzug gegeben werden.
◇ Die Klasse StringBuilder steht in keinerlei Ableitungsbeziehungen zu den Klassen StringBuffer und String. Allerdings implementiert sie ebenfalls die Interfaces CharSequence und Appendable.
◇ Die Klasse StringBuilder ist ebenfalls final und damit nicht ableitbar. •••• Konstruktoren der Klasse StringBuilder (analog zur Klasse StringBuffer)
•••• Memberfunktionen der Klasse StringBuilder Die Memberfunktionen entsprechen den Memberfunktionen der Klasse StringBuffer •••• Erzeugung eines String-Objekts aus einem StringBuilder-Objekt Die Möglichkeiten entsprechen denen der Klasse StringBuffer
◇ Mittels der StringBuilder-Memberfunktion :
◇ Mittels des String-Konstruktors :
◇ Mittels der statischen String-Memberfunktion :
public String toString()
public String(StringBuilder bld)
public static String valueOf(Object obj)
public StringBuilder() Erzeugt ein leeres StringBuilder-Objekt mit Kapazität von 16
public StringBuilder(int cap) Erzeugt ein leeres StringBuilder-Objekt, mit Kapazität = cap
public StringBuilder(String str) Erzeugt ein StringBuilder-Objekt, das mit dem Inhalt von str initialisiert ist, mit Kapazität = 16 + str.length()
public StringBuilder(CharSequence seq) Erzeugt ein StringBuilder-Objekt, das mit den in seq enthal- tenen Zeichen initialisiert ist, mit Kapazität = 16 + Anzahl Zeichen in seq
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 281 – 00 – TH – 02 -----------------------------------------------------------------------------------
Arrays in Java (1)
•••• Allgemeine Eigenschaften
◇ Arrays sind eine Zusammenfassung von Variablen, die in einer Reihenfolge geordnet sind und als Elemente bezeichnet werden.´ Alle Array-Elemente müssen vom gleichen Typ sein.
◇ Als Element-Typ ist jeder beliebige Typ (einfacher Datentyp oder Referenz-Typ) zulässig.
◇ Ein Array-Element wird über einen Index, der vom Typ int sein muß, ausgewählt. Der Index des ersten Elements hat den Wert 0.
◇ Arrays sind in Java Objekte. Array-Typen sind – namenlose – Klassen. Von einer Array-Klasse können keine weiteren Klassen abgeleitet werden.
◇ Array-Variable sind Referenz-Variable. Sie verweisen auf Array-Objekte. � Die Definition einer Array-Variablen erzeugt noch kein Array-Objekt, d.h. sie alloziert keinen Speicherplatz für die Array-Elemente.
◇ Eine Array-Variable legt nur den Element-Typ , nicht aber die Länge eines Arrays (d.h. die Anzahl seiner Elemente) fest. Sie kann daher auf Arrays beliebiger Länge zeigen.
◇ Die Länge eines Arrays wird dynamisch bei seiner Erzeugung (z.B. mittels eines new-Ausdrucks) festgelegt. Anschliessend ist sie nicht mehr veränderbar.
◇ Ein Array kann auch die Länge 0 besitzen. Ein derartiges Array ist ein echtes Array-Objekt. Sinnvoll können derartige Arrays beispielsweise als Rückgabewert von Funktionen (genauer : Referenz darauf) auf- treten.
◇ Jedes Array besitzt die öffentliche Datenkomponente public final int length; Sie enthält die Länge des Arrays.
◇ Ein Array-Zugriff wird zur Laufzeit auf Zulässigkeit überprüft. Der Versuch des Zugriffs zu einer nicht existierenden Array-Komponente (ungültiger Index) führt zum Werfen der Exception ArrayIndexOutOfBoundsException.
•••• Vereinbarung von Array-Variablen
◇ Angabe eines Array-Typs :
◇ Diese Typangabe ist bei der Vereinbarung von Array-Variablen zu verwenden. Beispiele : int[] ia; // ia kann auf Array-Objekte zeigen, deren Elemente int-Werte sind String[] names; // names kann auf Array-Objekte zeigen, deren Elemente Referenzen // auf String-Objekte sind
◇ Element-Typ eines Arrays kann wiederum ein Array sein � mehrdimensionale Arrays. Die Vereinbarung mehrdimensionaler Arrays erfolgt analog zu eindimensionalen Arrays. Beispiele : double[][] kmat; // kmat kann auf Array-Objekte zeigen, deren Elemente Referenzen auf // Array-Objekte sind, die double-Werte enthalten String[][] seite; // seite kann auf Array-Objekte zeigen, deren Elemente Referenzen // auf Array-Objekte sind, die Referenzen auf String-Objekte enthalten.
Element-Typ []
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 282 – 00 – TH – 01 -----------------------------------------------------------------------------------
Arrays in Java (2)
•••• Definition von Array-Objekten
◇ Definition von Array-Objekten mittels eines new-Ausdrucks. Dabei ist die Länge des Arrays explizit anzugeben. Die einzelnen Elemente werden mit ihrem Defaultwert initialisiert. Beispiele : ia = new int[10]; // Speicherallokation für ein Array-Objekt, das 10 int- // Elemente hat. Alle Elemente sind mit 0 initialisiert. names = new String[3]; // Speicherallokation für ein Array-Objekt, das 3 Elemente hat, // die Referenzen auf String-Objekte sind. // Alle Elemente sind mit null initialisiert.
◇ Die Definition eines Array-Objekts mittels eines new-Ausdrucks kann natürlich auch zusammen mit der Verein- barung einer Array-Variablen erfolgen. Beispiel : float[] pol = new float[6]; // pol zeigt auf ein alloziertes float-Array mit // 6 Elementen (die alle mit 0.0 initialisiert sind)
◇ Bei mehrdimensionalen Arrays kann im new-Ausdruck die Länge aller Dimensionen angegeben werden. Es reicht aber aus, nur die Länge der ersten (am weitesten links stehenden) Dimension festzulegen. Die Längen der übrigen Dimensionen müssen dann später festgelegt werden. Beispiel : kmat = new double[5][4]; // Speicherallokation für ein Array-Objekt, das 5 Elemente hat, // die auf gleichzeitig allozierte double-Arrays, die alle // 4 Elemente haben, zeigen. // Die Elemente der double-Arrays sind mit 0.0 initialisiert Das obige Beispiel ist eine abkürzende Schreibweise für die folgende ausführlichere Formulierung : kmat = new double[5][]; // Speicherallokation für ein Array-Objekt, das 5 Elemente hat, // die auf double-Arrays zeigen können, aber alle mit null // initialisiert sind. for (int i=0; i<kmat.length; i++)
kmat[i] = new double[4]; // Speicherallokation für 5 double-Arrays der Länge 4. // Alle Elemente dieser Arrays sind mit 0.0 initialisiert. Als Vorteil der Java-Implementierung von mehrdimensionalen Arrays ergibt sich, dass die Element-Arrays (Arrays in zweiter (und gegebenenfalls höherer) Dimension eine unterschiedliche Länge besitzen können.
◇ Definition von Array-Objekten mittels eines Array-Initialisierers (array initializer). Syntax : Ein Array-Initialisierer kann bei der Vereinbarung einer Array-Variablen angegeben werden. Er bewirkt die Allokation von Speicherplatz für ein Array-Objekt und initialisiert die einzelnen Elemente mit den angegebenen Initialisierungs-Ausdrücken. Die Länge des Arrays wird nicht angegeben .Sie ergibt sich aus der Anzahl der Initialisierungswerte Beispiel : String[] farben = { "rot", "gruen", "blau", "gelb", "weiss" }; // Vereinbarung der Array-Variablen farben. Diese zeigt auf ein gleichzeitig alloziertes Array- // Objekt, dessen 5 Elemente mit den Referenzen auf die angegeben Farb-Strings, für die ebenfalls // Speicher alloziert wird, initialisiert werden. Bei mehrdimensionalen Arrays können Array-Initialisierer geschachtelt werden (Initialisierungs-Ausdrücke sind wiederum Array-Initialisierer) Array-Initialisierer können auch zusammen mit einem new-Ausdruck verwendet werden. Sie sind dem new-Aus- druck nachzustellen, eine Array-Länge darf nicht angegeben werden. (sinnvoll zur Erzeugung anonymer Arrays)
Initialisierungs-Ausdruck {
,
}
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 283 – 00 – TH – 02 -----------------------------------------------------------------------------------
Arrays in Java (3)
•••• Arrays und Polymorphie
◇ Obwohl Array-Typen nicht ableitbar sind, kann auf sie – sofern es sich um Arrays von Referenz-Typen handelt – Polymorphie angewendet werden.
◇ Gegeben seien zwei Klassen X und Y. Die Klasse Y sei von der Klasse X abgeleitet. Die durch diese Vererbungsbeziehung definierte Polymorphie wird auch auf Arrays von Objekten dieser Klassen übertragen. Bezüglich der Polymorphie verhalten sich die Klassen Y[] und X[] also so, als ob sie voneinander abgeleitet wären. Einer Array-Variablen vom Typ X[] kann dadurch auch die Referenz auf ein Y[]-Objekt zugewiesen werden. Beispiel : Y[] yArr = new Y[3];
X[] xArr = yArr; // zulässig, da Y an X zuweisbar ist.
◇ Achtung : Den Elementen eines Referenz-Typ-Arrays dürfen nur Referenzen auf solche Objekte zugewiesen werden, die auch Variablen seines tatsächlichen Element-Typs zugewiesen werden können. Im obigen Beispiel dürfen den Elementen von xArr daher nur Referenzen auf Y-Objekte zugewiesen werden. Beispiel : xArr[0] = new Y(); // zulässig, da einer Y-Variablen eine Referenz auf ein Y-Objekt // zugewiesen werden kann xArr[1] = new X(); // unzulässig, da einer Y-Variablen keine Referenz auf ein X-Objekt // zugewiesen werden darf
◇ Die Zulässigkeit der Zuweisung an Elemente eines Referenz-Typ-Arrays wird zur Laufzeit überprüft. Beim Versuch einer unzulässigen Zuweisung wird eine Exception vom Typ ArrayStoreException geworfen. •••• Unterstützende Klassen der Standard-Bibliothek
◇ In der Java-Standardbibliothek sind zwei Klassen definiert, die statische Memberfunktionen zur Unterstützung der Verwendung von Arrays zur Verfügung stellen Beide Klassen können nicht instanziiert werden.
◇ Klasse java.lang.reflect.Array Sie stellt statische Methoden zur dynamischen Erzeugung von und zum Zugriff zu Arrays zur Verfügung.
◇ Klasse java.util.Arrays Sie stellt statische Methoden zur Bearbeitung von Arrays zur Verfügung. Im wesentlichen handelt es sich um Methoden - zum Suchen in Arrays - zum Sortieren von Array-Komponenten - zum Vergleich von Arrays - zur Zuweisung an Array-Bereiche
◇ Die Klasse java.lang.System definiert zum Kopieren von Arraybereichen die statische Methode
Quell-Objekt (src) und Ziel-Objekt (dest) müssen Arrays sein
X
Y
X[]
Y[]
wirkt sich hinsichtlich einer polymorphen Verwendung aus wie
public static void arraycopy(Object src, int sPos, Object dest, int dPos, int len)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 284 – 00 – TH – 03 -----------------------------------------------------------------------------------
Demonstrationsprogramm zu Arrays in Java •••• Quellcode des Programms (Klasse ArrayDemo)
•••• Ausgabe des Programms
public class ArrayDemo { public static void main(String[] args) { int[] ia; ia = new int[6]; System.out.println("int-Array : " + ia); for (int i=0; i<ia.length; i++) System.out.println(i + " : " + ia[i]); String[] names = /* new String[]*/ { "Walter", "Franz", "Ilka" }; System.out.println("String-Array :" + names); for (int i=0; i<names.length; i++) System.out.println(i + " : " + names[i]); double[][] kmat = new double[4][3]; System.out.println("2-dimensionales double-Array : " + kmat); for (int i=0; i<kmat.length; i++) System.out.println(i + " : " + kmat[i]); System.out.println("erstes Zeilen-Array :"); for (int i=0; i<kmat[0].length; i++) System.out.println(i + " : " + kmat[0][i]); System.out.println("weiteres 2-dimensionales double-Array :"); double[][] gmat = new double[4][]; for (int i=0; i<gmat.length; i++) gmat[i] = new double[i+1]; for (int i=0; i<gmat.length; i++) { System.out.print(i + " : "); for (int j=0; j<gmat[i].length; j++) System.out.print(gmat[i][j]+ " "); System.out.println(); } } }
int-Array : [I@108786b 0 : 0 1 : 0 2 : 0 3 : 0 4 : 0 5 : 0 String-Array :[Ljava.lang.String;@119c082 0 : Walter 1 : Franz 2 : Ilka 2-dimensionales double-Array : [[D@1add2dd 0 : [D@eee36c 1 : [D@194df86 2 : [D@defa1a 3 : [D@f5da06 erstes Zeilen-Array : 0 : 0.0 1 : 0.0 2 : 0.0 weiteres 2-dimensionales double-Array : 0 : 0.0 1 : 0.0 0.0 2 : 0.0 0.0 0.0 3 : 0.0 0.0 0.0 0.0
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 285 – 01 – TH – 01 -----------------------------------------------------------------------------------
Array-Listen in Java
•••• Eigenschaften von Array-Listen
◇ Array-Listen sind Datenstrukturen, die die Eigenschaften von Listen und Arrays kombinieren.
◇ Sowohl in Listen als auch in Arrays sind die Elemente alle vom gleichen Typ. In beiden Strukturarten sind die Elemente in einer linearen Reihenfolge angeordnet und damit damit über eine Positions- angabe referierbar. Der Zugriff zu einem Array-Element erfolgt dabei mittels Indizierung, die Zugriffszeit ist unabhängig von der Position. Der Zugriff zu einem Listen-Element erfolgt über eine Zugriffsfunktion, der die Position (Index) zu übergeben ist. Die Zugriffszeit hängt i.a. von der Position ab.
◇ Die Größe eines Arrays (d.h. die Anzahl der enthaltenen Elemente) ist i.a. feststehend und nicht veränderbar, während die Größe einer Liste variabel ist und jederzeit – durch das Einfügen oder Entfernen von Elementen – geändert werden kann.
◇ Array-Listen implementieren im Prinzip in der Größe veränderliche Arrays : - Bezüglich der Zugriffszeit zu einem Element verhalten sie sich wie Arrays (unabhängig von der Position) - Bezüglich der Elementeanzahl verhalten sie sich wie Listen, d.h. es können Elemente entfernt und hinzugefügt werden - Die Elemente werden über einen Index (int-Wert) referiert, das erste Element hat den Index 0. Der Zugriff erfolgt über eine Zugriffsfunktion.
•••• Realisierung von Array-Listen in Java
◇ Array-Listen werden in Java durch Objekte der Klasse ArrayList realisiert. Für diese Klasse gelten – im Gegensatz zu Arrays (namenlose Klassen !) – keine syntaktischen Besonderheiten. Array-Listen-Objekte werden mittels eines new-Ausdrucks erzeugt – mit gleicher Syntax wie für andere benamte Klassen.
◇ Array-Listen-Objekte können sich – wie Array-Objekte – im Element-Typ unterscheiden. � Es gibt unterschiedliche Array-Listen-Typen. � Die Klasse ArrayList ist eine generische Klasse (genaueres zu generischen Klassen s. später). Generische Klassen besitzen eine (oder mehrere) Typ-Parameter. Bei der Verwendung einer derartigen Klasse sind i.a. ein aktuelle Typ-Parameter anzugeben. Dadurch wird jeweils ein parameterisierter Typ definiert. Im vorliegenden Fall ist der Typ-Parameter der Typ der Array-Listen-Elemente. � Die verschiedenen Array-Listen-Typen sind also parameterisierte Typen, die durch die Klasse ArrayList definiert werden.
◇ Die exakte Klassenbezeichnung lautet ArrayList<E>. E ist der formale Typ-Parameter. Bei der Verwendung der Klasse (z.B. zur Objekterzeugung) ist E durch den jeweiligen Element-Typ als aktueller Typ-Parameter zu ersetzen, dieser muss ein Referenz-Typ sein (Unterschied zu Arrays !) Beispiel : ArrayList<String> salist = new ArrayList<String>(); ArrayList<String> ist die Typ-Bezeichnung für "ArrayListe mit String-Elementen" � Erzeugung eines Array-Listen-Objekts mit String-Elementen
◇ Anmerkung zur Implementierung : Ein Array-Listen-Objekt kapselt ein Array seines Element-Typs. Dieses Array besitzt eine Größe, die größer gleich der Anzahl der Array-Listen-Elemente ist. Sie wird als Kapazität der Array-Liste bezeichnet. Solange die Anzahl der Array-Listen-Elemente kleiner als die Kapazität ist, können problemlos neue Elemente hinzu- gefügt werden. Reicht die Kapazität zur Aufnahme eines neuen Elements nicht mehr aus, muss ein neues entsprechend größeres internes Array alloziert werden und der Inhalt des alten Arrays in das neue Array kopiert werden. � Zeitaufwand ( � sollte nicht zu häufig auftreten).
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 285 – 02 – TH – 01 -----------------------------------------------------------------------------------
Die Klasse ArrayList<E> in Java (1)
•••• Allgemeines
◇ Die generische Klasse ArrayList<E> befindet sich im Package java.util. Sie ist Bestandteil des Collection Frameworks.
◇ Sie dient zur Realisierung von Array-Listen
◇ Sie ist von der Klasse AbstractList<E> abgeleitet und implementiert die Interfaces List<E>, Cloneable, Serializable. RandomAccess, Iterable<E> und Collection<E>. •••• Konstruktoren der Klasse ArrayList<E> (Auswahl) •••• Memberfunktionen der Klasse ArrayList<E> (Auswahl)
◇
▻ Einfügen des Elements elem vom Typ E an das Ende der Array-Liste
▻ Funktionswert : true
◇
▻ Einfügen des Elements elem vom Typ E an der Position index.
▻ Ein an der Position index vorhandenes Element und alle danach kommenden Elemente werden um eine Position weitergeschoben
▻ Liegt index ausserhalb der Liste, wird eine IndexOutOfBoundsException geworfen
◇
▻ Entfernen des ersten Auftritts des Elements elem, dieses muß tatsächlich vom Typ E sein (Die Klasse Object ist Basisklasse für alle anderen Klassen in Java, jedes beliebige Element eines Refernztyps – d.h. jedes beliebige Objekt – kann daher als Instanz der Klasse Object betrachtet werden).
▻ Alle nach dem entfernten Element enthaltenen Elemente werden um eine Position nach vorn geschoben.
▻ Funktionswert : true, wenn das Element elem enthalten war, false, wenn das Element elem nicht enthalten war
◇
▻ Entfernen des Elements an der Position index.
▻ Alle nach dem entfernten Element enthaltenen Elemente werden um eine Position nach vorn geschoben.
▻ Funktionswert : das entfernte Element
▻ Liegt index ausserhalb der Liste, wird eine IndexOutOfBoundsException geworfen
◇
▻ Entfernen aller Elemente aus der Liste, die Liste ist anschliessend leer.
public ArrayList<E> Erzeugt ein leeres ArrayList-Objekt für Elemente des Typs E. Das Objekt hat eine Anfangs-Kapazität von 10. public ArrayList<E>(int initCap) Erzeugt ein leeres ArrayList-Objekt für Elemente des Typs E. Das Objekt hat eine Anfangs-Kapazität von initCap
public boolean add(E elem)
public void add(int index, E elem)
public boolean remove(Object elem)
public E remove(int index)
public void clear()
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 285 – 03 – TH – 01 -----------------------------------------------------------------------------------
Die Klasse ArrayList<E> in Java (2)
•••• Memberfunktionen der Klasse ArrayList<E> (Auswahl), Forts.
◇
▻ Auslesen des Elements an der Position index. (Die Liste bleibt unverändert)
▻ Funktionswert : das Element an der Position index.
▻ Liegt index ausserhalb der Liste, wird eine IndexOutOfBoundsException geworfen
◇
▻ Ersetzen des an der Position index befindlichen Elements durch das Element elem.
▻ Funktionswert : das Element, das sich zuvor an der Position index befunden hat..
▻ Liegt index ausserhalb der Liste, wird eine IndexOutOfBoundsException geworfen
◇
▻ Sicherstellung, dass die Kapazität mindestens minCap beträgt (falls erforderlich wird die Kapazität erhöht)
◇
▻ Ermittlung der Array-Listen-Größe (== Anzahl der enthaltenen Elemente)
▻ Funktionswert : Anzahl der enthaltenen Elemente
◇
▻ Übertragung des Listeninhalts – unter Beibehaltung der Element-Reihenfolge – in ein Array.
▻ Falls das als Parameter übergebene Array arr groß genug ist, wird der Listeninhalt in dieses Array übertragen, falls es zu klein ist, wird ein neues Array alloziert und als Ziel-Array verwendet.
▻ Falls das als Parameter übergebene Array arr größer als die Array-Liste ist, werden die nicht belegten Array- Elemente gleich null gesetzt.
▻ Funktionswert : Array, in das die Listenelemente übertragen wurden.
◇
▻ Übertragung des Listeninhalts – unter Beibehaltung der Element-Reihenfolge – in ein neu alloziertes Array, dessen Elementtyp tatsächlich E ist.
▻ Funktionswert : Array, in das die Listenelemente übertragen wurden. •••• Vergleich der Verwendung von Arrays und Arry-Listen
public E get(int index)
public E set(int index, E elem)
public void ensureCapacity(int minCap)
public int size()
public E[] toArray(E[] arr)
public Object[] toArray()
Array Array-Liste Variablen-Definition String[] a; ArrayList<String> a; Objekterzeugung a = new String[50]; a = new ArrayList<String>(); Schreiben a[i] = "Muenchen"; a.set(i, "München"); Lesen String s = a[i]; String s = a.get(i); Größenermittlung int len = a.length; int len = a.size();
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 285 – 04 – TH – 01 -----------------------------------------------------------------------------------
Demonstrationsprogramm zu ArrayListen in Java
•••• Quellcode des Programms (Klasse ArrayListDemo) •••• Probelauf des Programms
// ArrayListDemo.java import java.util.*; public class ArrayListDemo { public static void main(String[] args) { ArrayList<String> al = new ArrayList<String>(); System.out.println(); System.out.println("ArrayListe erzeugt, Laenge : " + al.size()); al.add("Muenchen"); al.add("Hamburg"); al.add("Berlin"); al.add("Koeln"); al.add("Stuttgart"); System.out.println("ArrayListe gefuellt, Laenge : " + al.size()); for (int i=0; i<al.size(); ++i) System.out.println(al.get(i)); String[] sa = new String[0]; sa = al.toArray(sa); System.out.println("Uebertragung in ein Array, Laenge : " + sa.length); for (int i=0; i<sa.length; ++i) System.out.println(sa[i]); } }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 286 – 01 – TH – 04 ------------------------------------------------------------------------------------
Die vereinfachte for-Anweisung in Java •••• Iteration über alle Elemente eines Arrays (und eines Containers)
◇ Zum sequentiellen Durchlaufen der Elemente eines Arrays wird üblicherweise die – auch aus C/C++ bekannte – (Standard-) for-Anweisung eingesetzt. Zum Zugriff zu den Elementen erfordert sie die explizite Definition und Verwendung einer "Laufvariablen".
◇ Beispiel : double[] da; // ... for (int i=0; i<da.length; i++)
System.out.println(da[i]);
◇ Analoges gilt für das Durchlaufen eines Containers (in Java Collection genannt). Anstelle der Laufvariablen tritt hier ein Iterator-Objekt. •••• Vereinfachte for-Anweisung (Enhanced for Loop, For-Each-Schleife)
◇ Sie wurde mit dem JDK 5.0 zum sequentiellen Durchlaufen aller Elemente eines Arrays (bzw einer Collection) ein- geführt
◇ Bei ihr wird auf die explizite Definition einer Laufvariablen (bzw eines Iterator-Objekts) verzichtet.
◇ Syntax :
◇ Beispiel : double[] da; // ... for(double el : da)
System.out.println(el);
◇ Wirkung : "Für jedes Element el in da " Der Element-Typ-Variablen el wird in jedem Schleifendurchlauf das jeweils nächste Element des Arrays da zugewiesen.
◇ Die Gültigkeit der Element-Typ-Variablen el ist auf den Schleifenrumpf begrenzt.
◇ Der vom Compiler erzeugte Code benötigt und verwaltet auch hier für den Elementzugriff eine Laufvariable (bzw ein Iterator-Objekt). Diese wird vom Compiler implizit erzeugt. •••• Anwendbarkeit der vereinfachten for-Anweisung
◇ Sie ist kein allgemeiner Ersatz für die (Standard-) for-Anweisung
◇ Sie kann nur zum sequentiellen Durchlaufen aller Elemente eines Arrays (bzw einer Collection) in Vorwärtsrichtung eingesetzt werden (vom ersten zum letzten Element, ohne Überspringen einzelner Elemente)
◇ Sie kann nicht eingesetzt werden, wenn
▻ ein Element aus dem Array (der Collection) entfernt werden soll
▻ ein Element innerhalb des Arrays (der Collection) modifiziert werden soll
▻ innerhalb einer Schleife mehrere Arrays (Collections) parallel bearbeitet werden sollen
◇ Ihr Einsatz in geschachtelten Schleifen ist jedoch möglich Beispiel : Durchlaufen eines zweidimensionalen Arrays double[][] gmat; // ... for (double[] row : gmat)
for (double el : row) System.out.println(el);
Element-Typ ( : ) for Var-Name
Collection-Objekt
Array-Objekt
Anweisung
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 286 – 02 – TH – 03 ------------------------------------------------------------------------------------
Demonstrationsprogramm zur vereinfachten for-Anweisung in Java
•••• Quellcode des Programms (Klasse ForEachDemo)
•••• Ausgabe des Programms
// ForEachDemo.java public class ForEachDemo { public static void main(String[] args) { double[] da; da = new double[6]; for (int i=0; i<da.length; i++) da[i] = i; System.out.println("\ndouble-Array (eindimensional) : "); for(double el : da) System.out.println(el); String[] names = { "Walter", "Franz", "Ilka" }; System.out.println("\nString-Array : "); for (String str : names) System.out.println(str); System.out.println("\ndouble-Array (zweidimensional) :"); double[][] gmat = new double[4][]; for (int i=0; i<gmat.length; i++) gmat[i] = new double[i+1]; for (double[] row : gmat) { for (double el : row) System.out.print(el + " "); System.out.println(); } } }
double-Array (eindimensional) : 0.0 1.0 2.0 3.0 4.0 5.0 String-Array : Walter Franz Ilka double-Array (zweidimensional) : 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 291 – 00 – TH – 04 ------------------------------------------------------------------------------------
Die Klasse Object in Java (1)
•••• "Mutter" aller Klassen
◇ In Java existiert nur eine Klassenhierarchie. Wurzel dieser Hierarchie ist die Klasse Object. � Alle Klassen haben – direkt oder indirekt – diese Klasse als Basisklasse. Auch Klassen, die scheinbar nicht abgeleitet sind, d.h. die ohne Angabe einer Basisklasse definiert sind, sind tatsäch- lich implizit von Object abgeleitet.
◇ Da eine Variable eines Klassen-Typs auch auf Objekte abgeleiteter Klassen zeigen kann (Laufzeit-Polymorphie !), kann eine Variable vom Typ Object Objekte eines beliebigen Klassen-Typs (einschliesslich Array-Typs) referieren.
◇ Die Klasse Object ist im Package java.lang enthalten.
•••• Memberfunktionen der Klasse Object
◇ Die Klasse Object definiert insgesamt elf Memberfunktionen, die wegen der Vererbung in allen Klassen zur Ver- fügung stehen.
◇ Sechs dieser Memberfunktionen sind nicht überschreibbar. Die übrigen lassen sich in abgeleiteten Klassen überschreiben. In Abhängigkeit von der jeweiligen Klasse kann für eine sinnvolle Funktionalität ein Überschreiben notwendig sein.
◇ Die Memberfunktionen von Object zerfallen in zwei Kategorien : - Allgemeine Utility-Funktionen - Methoden zur Thread-Unterstützung Hier werden nur kurz die Utilility-Funktionen vorgestellt. Auf die Methoden zur Thread-Unterstützung wird später im Rahmen der Besprechung von Threads eingegangen.
◇
▻ Die Funktion vergleicht das aktuelle Objekt mit dem durch obj referierten Objekt. Sie liefert true als Funktionswert, wenn Gleichheit vorliegt, andernfalls false.
▻ Grundsätzlich ist die Funktion für eine Überprüfung auf Wert-Gleichheit der Objekte vorgesehen.
▻ Die Default-Implementierung in der Klasse Object geht davon aus, dass ein Objekt nur zu sich selbst gleich sein kann, d.h. sie setzt Wert-Gleichheit mit Referenz-Gleichheit (Identität) gleich. Sie liefert genau dann true, wenn obj das aktuelle Objekt referiert (obj==this).
▻ Für die Implementierung einer echten Wert-Gleichheit, die sich auf den Inhalt (Zustand) der referierten Objekte bezieht, muss die Methode in abgeleiteten Klassen geeignet überschrieben werden. Dies ist für zahlreiche Klassen der Standard-Bibliothek, u.a. auch für die Klasse String, erfolgt.
◇
▻ Die Funktion liefert einen Hash-Code für das aktuelle Objekt. Jedes Objekt besitzt einen derartigen Hash-Code. Er ermöglicht die Speicherung von Objekten in Hash-Tabellen (z.B. Klasse java.util.Hashtable).
▻ Der Hash-Code eines Objekts darf sich während der Ausführung einer Java-Applikation nicht ändern. Bei unterschiedlichen Ausführungen derselben Applikation kann er dagegen unterschiedlich sein.
▻ Die Default-Implementierung in der Klasse Object liefert für unterschiedliche Objekte unterschiedliche Hash-Codes (Typischerweise ist dieser gleich der in einen int-Wert umgewandelten Speicheradresse des Objekts).
▻ Wenn für die zwei durch x und y referierten Objekte x.equals(y) den Wert true liefert, muß der für die beiden Objekte erzeugte Hash-Code auch gleich sein (x.hashCode()==y.hashCode())
▻ Daher ist es bei Überschreiben der Funktion equals() i.a. auch notwendig die Funktion hashCode() entsprechend zu überschreiben.
public boolean equals(Object obj)
public int hashCode()
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 292 – 00 – TH – 06 ------------------------------------------------------------------------------------
Die Klasse Object in Java (2) •••• Memberfunktionen der Klasse Object, Forts.
◇
▻ Die Funktion liefert ein neues Objekt, dass ein Clone (eine Kopie) des aktuellen Objekts ist.
▻ Die tatsächliche Klasse des aktuellen Objekts muß das Interface Cloneable implementieren.
▻ Die Default-Implementierung in der Klasse Object prüft, ob für das aktuelle Objekt das Interface Cloneable implementiert ist. Ist das nicht der Fall, wird die Exception CloneNotSupportedException geworfen. Falls es implementiert ist, wird ein neues Objekt der Klasse erzeugt, dessen Datenkomponenten mit den Werten der entsprechenden Datenkomponenten des aktuellen Objekts initialisiert werden. ("flache" Kopie, shallow copy)
▻ Soll das neue Objekt als "tiefe" Kopie (deep copy) erzeugt werden, muss clone() geeignet überschrieben werden.
▻ Die Klasse Object selbst implementiert das Interface Cloneable nicht. Das bedeutet, dass der Aufruf von clone() für ein Objekt der Klasse Object zum Werfen der Exception CloneNotSupportedException führt.
◇
▻ Die Funktion liefert eine String-Repräsentation des aktuellen Objekts.
▻ Die Default-Implementierung in der Klasse Object erzeugt ein String-Objekt, dessen Inhalt aus dem Klassennamen des aktuellen Objekts, dem Zeichen '@' und der sedezimalen Darstellung seines Hash-Codes zusammengesetzt ist.
▻ Soll eine andere das Objekt kennzeichnende String-Darstellung erzeugt werden, muss die Methode toString() geeignet überschrieben werden
▻ Die Methode toString() wird immer dann implizit aufgerufen, wenn eine Objekt-Referenz in einem String- Konkatenations-Ausdruck auftritt.
◇
▻ Die Funktion liefert die Instanz der Klasse Class<T>, die die tatsächliche Klasse des aktuellen Objekts beschreibt. Der Typ-Parameter T steht für die repräsentierte Klasse (allgemein : für den repräsentiertenTyp)
▻ Die Klasse Class ist eine wesentliche Komponente der Reflection-Fähigkeit von Java (enthalten im Package java.lang). Objekte dieser Klasse repräsentieren andere Klassen (sowie Interfaces und die primitiven Datentypen) und stellen charakteristische Informationen über diese zur Verfügung. Sie können nicht explizit erzeugt werden (es gibt keinen öffentlichen Konstruktor), sondern werden durch die JVM beim Laden einer Klasse automatisch generiert.
▻ U.a. stellt die Klasse Class die Memberfunktion public String getName() zur Verfügung. Diese liefert den vollqualifizierten Namen der repräsentierten Klasse als String zurück.
▻ Die Methode getClass() kann nicht überschrieben werden.
◇
▻ Diese Funktion wird vom Garbage Collector für ein Objekt aufgerufen, für das keine Referenz mehr existiert und das anschliessend vernichtet werden soll.
▻ Der Zweck dieser Funktion liegt in der Durchführung von Bereinigungsaufgaben vor der endgültigen Objekt- vernichtung (z.B. Freigabe von Resourcen, wie z.B. I/O-Verbindungen oder Schließen von Dateien usw). Die Funktion kann somit als eine Art Ersatz für einen Destruktor aufgefasst werden.
▻ Die Default-Implementierung in der Klasse Object führt keinerlei Aktionen aus.
▻ Sollen für Objekte einer bestimmten Klasse spezielle Bereinigungsaktionen ausgeführt werden, muss die Funktion für diese Klasse überschrieben werden.
protected Object clone() throws CloneNotSupportedException
public String toString()
public final Class<?> getClass()
protected void finalize() throws Throwable
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 293 – 00 – TH – 01 -----------------------------------------------------------------------------------
Die Klasse Object in Java (3)
•••• Demonstrationsprogramm zu Memberfunktionen der Klasse Object
•••• Ausgabe des Programms
// ObjTest.java public class ObjTest implements Cloneable { private String name; public ObjTest(String str) { name=str; } public String toString() { return super.toString()+" ("+name+")"; } public static void main(String[] args) { ObjTest o1 = new ObjTest("Test1"); System.out.println("o1.toString() : " + o1.toString()); Object o2 = new ObjTest("Test2"); System.out.println("o2 : " + o2); System.out.println("o1.hashCode() : " + o1.hashCode()); System.out.println("o2.hashCode() : " + o2.hashCode()); System.out.println("o2.equals(o1) : " + o2.equals(o1)); o2=o1; System.out.println("\nnach o2=o1 :"); System.out.println("o2 : " + o2); System.out.println("o2.equals(o1) : " + o2.equals(o1)); try { o2=o1.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()); } System.out.println("\nnach o2=o1.clone() :"); System.out.println("o2 : " + o2); System.out.println("o2.equals(o1) : " + o2.equals(o1)); } }
o1.toString() : ObjTest@119c082 (Test1) o2 : ObjTest@1add2dd (Test2) o1.hashCode() : 18464898 o2.hashCode() : 28168925 o2.equals(o1) : false nach o2=o1 : o2 : ObjTest@119c082 (Test1) o2.equals(o1) : true nach o2=o1.clone() : o2 : ObjTest@eee36c (Test1) o2.equals(o1) : false
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2A1 – 00 – TH – 03 ------------------------------------------------------------------------------------
Aufzählungstypen in Java (1) •••• Allgemeines
◇ Aufzählungstypen wurden mit dem JDK 5.0 in Java eingeführt
◇ Sie ermöglichen die Definition von Wertemengen, die keinen semantischen Bezug zu Zahlen oder logischen Werten haben.
◇ Die einzelnen Werte, aus denen ein Aufzählungstyp besteht (Enum-Werte), besitzen einen bei der Typdefinition festgelegten Namen. Ausserdem ist jedem Enum-Wert eine durch die Definitions-Reihenfolge festgelegte Ordnungszahl zugeordnet. Der erste Wert besitzt die Ordnungszahl 0, der zweite die Ordnungszahl 1 usw.
◇ Werte in verschiedenen Aufzählungstypen können den gleichen Namen besitzen.
◇ Java-Aufzählungstypen sind – anders als C/C++-Aufzählungstypen – typsicher : Der Compiler stellt sicher, dass einer Aufzählungstyp-Variablen nur gültige Werte ihres Aufzählungstyps zugewiesen werden können.
◇ Anders als in C/C++ steht der Name eines Enum-Werts auch zur Laufzeit zur Verfügung und kann z.B. ausgegeben werden.
◇ Enum-Werte können als case-Label in switch-Anweisungen verwendet werden.
•••• Definition
◇ In der einfachsten Form (elementare Definition) werden Aufzählungstypen wie in C/C++ definiert. Beispiele ; enum Jahreszeit { WINTER, FRUEHLING, SOMMER, HERBST }; enum Farbe { ROT, GRUEN, BLAU, GELB, GRAU };
◇ Über die Möglichkeiten von C/C++ hinausgehend können auch noch komplexere Formen der Typ-Definition verwendet werden.
•••• Verwendung
◇ Aufzählungstypen können wie andere Typen verwendet werden, z.B. zur Definition von Variablen Beispiele : Jahreszeit saison; Farbe anstrich;
◇ Aufzählungstyp-Werte (Enum-Werte) werden mit ihrem vollqualifizierten Namen angesprochen :
◇ Aufzählungstyp-Variablen können Aufzählungstyp-Werte zugewiesen werden. Beispiele : saison = Jahreszeit.SOMMER; anstrich = Farbe.GRUEN;
◇ Anders als in C/C++ sind zwischen Enum-Werten und int-Werten weder implizite noch explizite Typ- Konvertierungen möglich.
Wert-Name {
,
} enum ; Typ-Name
Wert-Name . Typ-Name
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2A2 – 00 – TH – 03 ------------------------------------------------------------------------------------
Aufzählungstypen in Java (2)
•••• Implementierung
◇ Aufzählungstypen in Java sind Klassen, die besondere Eigenschaften besitzen Aufzählungstyp-Variable sind somit Referenz-Variable.
◇ Alle Aufzählungstypen sind implizit von der abstrakten Bibliotheksklasse Enum abgeleitet. (Package java.lang) Diese besitzt u.a. je eine Datenkomponente zur Speicherung des Namens des Aufzählungstyp-Werts (Typ String) sowie der dem Wert zugeordneten Ordnungszahl (Typ int)
◇ Die einzelnen Aufzählungstyp-Werte sind Objekte ihrer jeweiligen Klasse (Enum-Objekte). Sie werden implizit beim Laden der Klasse erzeugt und als öffentlich zugreifbare statische Datenkomponenten gespeichert. (Verwendung über ihren vollqualifizierten Namen !, s. oben) Eine explizite Instantierung einer Aufzählungstyp-Klasse ist nicht möglich.
◇ Wie jede Klasse kann ein Aufzählungstyp auch Memberfunktionen und weitere Datenkomponenten besitzen.
◇ Neben den für jeden Aufzählungstyp standardmässig vorhandenen Memberfunktionen (teilweise geerbt von Object und Enum) können bei seiner Definition weitere Methoden und Datenkomponenten festgelegt werden. •••• Standardmässig definierte Memberfunktionen von Aufzählungstypen (Auswahl) E bezeichnet den jeweiligen Aufzählungstyp
◇
▻ Die Funktion gibt ein Array zurück, das alle Aufzählungstyp-Werte (Enum-Objekte !) in der Reihenfolge ihrer Definition enthält
◇
▻ Die Funktion liefert den Namen des aktuellen Aufzählungstyp-Wertes (Enum-Objektes) zurück.
◇
▻ Die Funktion liefert die Ordnungszahl, die mit dem aktuellen Enum-Objekt verknüpft ist, zurück
▻ Die Ordnungszahl entspricht der Reihenfolge der Enum-Objekte (Enum-Werte) in der Typ-Definition. Der erste Enum-Wert hat die Ordnungszahl 0.
◇
▻ Die Funktion vergleicht das aktuelle Enum-Objekt mit dem als Parameter übergebenen Enum-Objekt bezüglich ihrer Ordnungszahlen
▻ Das aktuelle Enum-Objekt und das Parameter-Enum-Objekt müssen vom gleichen Aufzählungstyp sein
▻ Funktionswert : <0, wenn das aktuelle Objekt < dem Parameter-Objekt ist ==0, wenn das aktuelle Objekt == dem Parameter-Objekt ist >0, wenn das aktuelle Objekt < dem Parameter-Objekt ist
◇
▻ Die Funktion vergleicht das aktuelle Enum-Objekt mit dem als Parameter übergebenen Objekt
▻ Funktionswert : true, wenn das Parameter-Objekt gleich dem aktuellen Enum-Objekt ist false, wenn das Parameter-Objekt nicht gleich dem aktuellen Enum-Objekt ist
public String toString() /* definiert in Enum */
public static E[] values() /* automatisch vom Compiler generiert */
public final int ordinal() /* definiert in Enum */
public final int compareTo(E obj) /* definiert in Enum */
public final boolean equals(Object obj) /* definiert in Enum */
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2A3 – 00 – TH – 03 ------------------------------------------------------------------------------------
Aufzählungstypen in Java (3) •••• Aufzählungstypen mit selbstdefinierten Methoden und Datenkomponenten
◇ Aufzählungstypen können mit einer beliebigen Anzahl zusätzlicher Memberfunktionen und Datenkomponenten definiert werden. Dies eröffnet ein weites Spektrum an Gestaltungsmöglichkeiten für sehr effizient einsetzbare Aufzählungstypen.
◇ Für die entsprechenden Aufzählungstyp-Definitionen gilt eine erweiterte komplexere Syntax.
◇ Üblicherweise gilt eine Memberfunktion für alle Objekte des entsprechenden Typs. Sie legt ein für alle Objekte gleich- artiges Verhalten fest. Bei Aufzählungstypen besteht darüberhinaus die Möglichkeit, für jeden Enum-Wert (Enum-Objekt) ein spezifisches Verhalten festzulegen. Hierzu kann man die entsprechende Methode in der Aufzählungstyp-Definition als abstract deklarieren und sie dann für jeden Enum-Wert konkret definieren. (� wert-spezifische Methoden, constant specific methods)
◇ Beispiel für einen Aufzählungstyp mit selbstdefinierter für alle Enum-Werte geltender Memberfunktion :
◇ Wenn ein Aufzählungstyp mit zusätzlichen Datenkomponenten definiert wird,
▻ muss auch ein Konstruktor definiert werden, mit dem die Datenkomponenten initialisiert werden können
▻ und müssen für jeden Enum-Wert entprechende aktuelle Werte für die Datenkomponenten bereitgestellt werden. Anmerkung : Auch wenn der Konstruktor public definiert wird, lassen sich explizit keine Enum-Objekte anlegen.
◇ Beispiel für einen Aufzählungstyp mit einer zusätzlichen Datenkomponente
enum Wochentag { Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, Sonntag; public boolean istWochenende() {
return this==Samstag || this==Sonntag;
}
};
enum Jahreszeit2 { WINTER ("Dezember bis Februar"), FRUEHLING("Maerz bis Mai"), SOMMER ("Juni bis August"), HERBST ("September bis Oktober"); private String bereich; public Jahreszeit2 (String monate) {
bereich = monate;
}
public String getBereich() { return bereich; } };
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2A4 – 00 – TH – 03 ------------------------------------------------------------------------------------
Demonstrationsprogramm zu Aufzählungstypen in Java •••• Quellcode des Programms (Klasse EnumDemo2)
•••• Ausgabe des Programms
// EnumDemo2.java enum Wochentag { Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, Sonntag; public boolean istWochenende() { return this==Samstag || this==Sonntag; } }; enum Jahreszeit2 { WINTER ("Dezember bis Februar"), FRUEHLING("Maerz bis Mai"), SOMMER ("Juni bis August"), HERBST ("September bis Oktober"); private String bereich; public Jahreszeit2 (String monate) { bereich = monate; } public String getBereich() { return bereich; } }; public class EnumDemo2 { public static void main(String[] args) { Wochentag tag = Wochentag.Samstag; System.out.println(); System.out.println(tag + " gehoert zum Wochenende : " + tag.istWochenende()); Jahreszeit2 saison = Jahreszeit2.HERBST; System.out.println("aktuelle Jahreszeit : " + saison); System.out.println("\nDie Jahreszeiten :"); for (Jahreszeit2 jz : Jahreseit2.values()) System.out.println(jz + " umfasst " + jz.getBereich()); } }
Samstag gehoert zum Wochenende : true aktuelle Jahreszeit : HERBST Die Jahreszeiten : WINTER umfasst Dezember bis Februar FRUEHLING umfasst Maerz bis Mai SOMMER umfasst Juni bis August HERBST umfasst September bis Oktober
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2B1 – 00 – TH – 03 ------------------------------------------------------------------------------------
Generische Programierung in Java (1) •••• Allgemeines
◇ Unter generischer Programmierung versteht man die Formulierung von Programm-Code, der in seiner wesentlichen Funktionalität unabhängig von Repräsentationsdetails konkreter Datentypen ist. Der Code wird einmal allgemein formuliert und lässt sich dann für unterschiedliche konkrete Datentypen verwenden.
◇ Ein typisches Beispiel für generische Programmierung bilden i.a. Container-Bibliotheken (z.B. STL in C++, Collection Framework in Java). Container speichern und verwalten Daten (Objekte) unterschiedlicher Typen. Ihre jeweilige Funktionalität ist dabei i.a. unabhängig von den konkreten Typen der Daten. Beispiel : Ein Stack für Integer-Werte besitzt die gleiche Funktionalität wie ein Stack für Strings oder ein Stack für Person-Objekte.
◇ Generische Programmierung lässt sich realisieren mittels
▻ Polymorphie (zumindest eingeschränkt)
▻ Typ-Parameterisierung
◇ In C++ wird generische Programmierung durch den Einsatz von Klassen- und/oder Funktions-Templates ermöglicht, die mit Typ-Parametern arbeiten •••• Generische Programmierung in Java bis einschliesslich dem JDK 1.4
◇ Für eine – eingeschränkte – generische Programmierung steht lediglich das Konzept der Polymorphie zur Verfügung.
◇ Beispielweise verwalten die Container des Collection Frameworks Objekte der Klasse Object. Da in Java jede Klasse direkt oder indirekt von Object abgeleitet ist, können die Container für Daten beliebigen Referenz-Typs eingesetzt werden. Das Collection Framework ist somit generisch programmiert. Auch in anderen Stellen der Java Standard-Bibliothek wird diese Art der generischen Programmierung verwendet.
◇ Im Code, der derartigen Code – z.B.das Collection Framework – verwendet, müssen gegebenenfalls explizite Type- Casts in den tatsächlich konkret verwendeten Datentyp vorgenommen werden. Der Anwendungsprogrammierer ist für die Wahl der richtigen Type-Casts verantwortlich. Die Verwendung falscher Typ-Casts kann vom Compiler i.a. nicht erkannt werden, sondern wird erst durch das Auftreten von Laufzeitfehlern entdeckt.
◇ Beispiel :
// GenProgDemo14.java // Demonstration der Anwendung generischer Programmierung mittels Polymorphie // (bis JDK 1.4) import java.util.*; public class GenProgDemo14 { public static void main(String[] args) { Stack stk = new Stack(); stk.push(new Integer(123)); Integer i = (Integer)stk.pop(); // expliziter Type-Cast erforderlich ! System.out.println("Wert vom Stack : " + i); stk.push("Ein String"); // fehlerfrei uebersetzt i = (Integer)stk.pop(); // Laufzeitfehler ClassCastException } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2B2 – 00 – TH – 02 -----------------------------------------------------------------------------------
Generische Programierung in Java (2) •••• Generische Programmierung in Java ab dem JDK 1.5
◇ Mit dem JDK 1.5 wurde in Java das Konzept der Generics als neues Sprachelement eingeführt. Dieses sieht die Definition generischer Klassen (und Interfaces) sowie generischer Methoden (einschliesslich gene- rischer Konstruktoren) vor. Dadurch lässt sich nunmehr auch in Java eine auf Typ-Parameterisierung basierende generische Programmierung realisieren.
◇ Generics in Java weisen eine formale Ähnlichkeit zu den Templates in C++ auf. Sie unterscheiden sich aber grund- legend von diesen bezüglich ihrer Implementierung und ihrer Behandlung durch den Compiler.
◇ Mit der Definition einer generischen Klasse (bzw eines generischen Interfaces) werden formale Typ-Parameter festgelegt. Diese werden in Java auch als Typ-Variable (Type Variable) bezeichnet. Die formalen Typ-Parameter werden nach dem Klassennamen (bzw Interface-Namen) angegeben, in spitzen Klammern eingeschlossen und durch Kommata getrennt � Klassenbezeichnung einer generischen Klasse (bzw eines Interfaces). Syntax : Die Namen der Typ-Parameter sollten per Konvention möglichst nur aus einem Grossbuchstaben bestehen. Beispiele : Stack<E> Map<K,V>
◇ Zur Verwendung einer generischen Klasse (bzw eines generischen Interfaces) müssen die formalen Typ-Parameter durch aktuelle Typ-Parameter ersetzt werden. Diese werden in der Java-Syntax als Typ-Argumente (Type Arguments) bezeichnet. (Es muss sich um Referenz-Typen handeln. Einfache Datentypen sind nicht zulässig.) Hierdurch wird ein aus der generischen Klasse (bzw eines Interfaces) erzeugter konkreter Typ festgelegt � parameteriserter Typ Syntax : Durch jeden neuen Satz von Typ-Argumenten wird ein neuer parameterisierter Typ definiert. Eine generische Klasse (bzw ein generisches Interface) definiert also mehrere (i.a. beliebig viele) Typen.
◇ Die Verwendung von parameterisierten Typen vereinfacht die Programmierung, explizite Type-Casts sind nicht mehr erforderlich. Der Compiler kann die fehlerhafte Verwendung parameteriserter Typen erkennen. Es wird typsicherer Code erzeugt.
◇ Beispiel :
Typ-Parameter <
,
> Klassen-Name
Typ-Argument <
,
> Klassen-Name
// GenProgDemo15.java // Demonstration der Anwendung generischer Programmierung mittels // Typ-Parameterisierung (Generics, ab JDK 1.5) import java.util.*; public class GenProgDemo15 { public static void main(String[] args) { Stack<Integer> stk = new Stack<Integer>(); stk.push(new Integer(123)); // oder : stk.push(123); Integer i = stk.pop(); // expliziter Type-Cast nicht erforderlich System.out.println("Wert vom Stack : " + i); stk.push("Ein String"); // Compiler-Fehler } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2B3 – 00 – TH – 01 -----------------------------------------------------------------------------------
Generische Programierung in Java (3) •••• Parameterisierte Typen und Vererbung
◇ Eine eventuelle Ableitungsbeziehung zwischen Typ-Argumenten wird nicht auf die entsprechenden parameteri- sierten Typen übertragen (Unterschied zu Arrays !) � Typ-Invarianz
◇ Beispiel : Die Klasse Integer ist von der Klasse Number abgeleitet. Eine Number-Variable kann damit auch auf ein Integer-Objekt zeigen : Number num = new Integer(25); Dagegen besteht zwischen den parameterisierten Typen Stack<Integer> und Stack<Number> keinerlei Kompatibilität : Stack<Number> = new Stack<Integer>() // unzulässig !!!
◇ Eine der Vererbung entsprechende Kompatibilitätsbeziehung zwischen parameterisierten Datentypen wird durch die Verwendung von Wildcards und Typbegrenzungen (Type Bounds) bei den Typ-Argumenten ermöglicht •••• Wildcards als Typ-Argumente
◇ Die Verwendung des Wildcard-Zeichens ? als Typ-Argument definiert einen parameterisierten Typ, zu dem alle anderen aus derselben generischen Klasse erzeugbaren Typen zuweisungs-kompatibel sind. Dieser Wildcard-Typ wirkt als eine Art "Basisklasse" aller anderen parameterisierten Typen derselben Klasse.
◇ Beispiel : Stack<?> stk = new Stack<Integer>(); // zulässig !!! stk = new Stack<Number>(); // zulässig !!! stk = new Stack<String>(); // zulässig !!!
◇ Wildcard-Typen sind nur eingeschränkt verwendbar. Sie eignen sich nur für Situationen, die keine Festlegung auf ein konkretes Typ-Argument benötigen Beispielsweise lässt sich eine Utility-Methode zum Leeren eines beliebigen Stacks mit einem Parameter vom Typ Stack<?> definieren :
◇ Aus der Sicht des Compilers sind die Eigenschaften eines Wildcard-Typs bezüglich seiner Typ-Argumente völlig unbekannt. Er kann daher bezüglich der Verwendung der Typ-Argumente keine Überprüfungen vornehmen. Deshalb sind sowohl Lese- als auch Schreibzugriffe, die von den Typ-Argumenten abhängen, nicht zulässig. Ausnahmen : - Da jedes Typ-Argument von Object abgeleitet sein muss, ist ein Lesen von Object-Objekten immer zulässig (z.B. können Integer-Objekte jederzeit als Object-Objekte gelesen werden) - Der Wert null kann jeder Referenz-Variablen zugewiesen werden. Daher kann null immer als ein zu jedem Typ-Argument kompatibler Wert geschrieben werden (z.B. kann auf jedem beliebigen Stack der Wert null abgelegt werden).
// GenProgWildcardDemo.java import java.util.*; public class GenProgWildcardDemo { public static void main(String[] args) { Stack<Integer> stk = new Stack<Integer>(); stk.push(3); stk.push(5); stk.push(7); System.out.println("Stack enthielt " + clearStack(stk) + " Elemente"); }
public static int clearStack(Stack<?> s) // Rueckgabe Anzahl entfernter Elemente { int i = 0; while (!s.empty()) { s.pop(); ++i; } return i; } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 2B4 – 00 – TH – 02 -----------------------------------------------------------------------------------
Generische Programierung in Java (4) •••• Typbegrenzte Wildcards als Typ-Argumente
◇ Zu einem Wildcard-Typ mit dem Typ-Argument ? sind alle aus derselben Klasse erzeugbaren parameterisierten Typen kompatibel. Häufig wird aber eine eingeschränkte Kompatibiltät benötigt, die auf die Berücksichtigung der zwischen den Typ- Argumenten bestehenden Ableitungsbeziehungen begrenzt ist.
◇ Derartige eingeschränkte Kompatibilitäten werden durch typbegrenzte Wildcards (bounded wildcards) als Typ- Argumente realisiert. Es gibt zwei Arten der Begrenzung :
▻ Wildcards mit oberer Begrenzung (Upper Type Bound)
▻ Wildcards mit unterer Begrenzung (Lower Type Bound)
◇ Wildcards mit oberer Begrenzung (covarianter Wildcard-Typ): Zu einem parameterisierten Typ mit einem derartigen Typ-Argument sind alle Typen kompatibel deren Typ-Argument gleich der oberen Begrenzung ist oder von dieser abgeleitet ist Syntax : Beispiel : Stack<? extends Number> stk;
Hierzu sind alle Stack-Typen kompatibel, deren Typ-Argument der Typ Number oder ein davon abgeleiteter Typ ist : stk = new Stack<Integer>(); // zulässig !!! stk = new Stack<Object>(); // unzulässig !!! Allgemein gilt : C<A> ist kompatibel zu C<? extends B>, wenn A kompatibel ist zu (abgeleitet ist von) B Bei Wildcard-Typen mit oberer Begrenzung sind Schreibzugriffe, die von den Typ-Argumenten abhängen, grund- sätzlich nicht zulässig. (Ausnahme : Schreiben des Wertes null). Lesezugriffe dagegen sind erlaubt, da ein Objekt einer abgeleiteten Klasse immer als Objekt einer seiner Basisklassen verwendet werden kann. Z.B. ist ein Integer-Objekt immer auch ein Number-Objekt, d.h. es kann als solches ausgelesen werden. Umgekehrt kann ein Number-Objekt nicht als Integer-Objekt behandelt werden, was beim Schreiben eines Number-Objekts in einen – konkret vorhandenen – Integer-Stack notwendig wäre.
◇ Wildcards mit unterer Begrenzung (contravarianter Wildcard-Typ): Zu einem parameterisierten Typ mit einem derartigen Typ-Argument sind alle Typen kompatibel deren Typ-Argument gleich der unteren Begrenzung ist oder ein Basis-Typ dieser ist Syntax : Beispiel : Stack<? super Number> stk;
Hierzu sind alle Stack-Typen kompatibel, deren Typ-Argument der Typ Number oder ein Basis- Typ von Number ist : stk = new Stack<Integer>(); // unzulässig !!! stk = new Stack<Object>(); // zulässig !!! Allgemein gilt : C<A> ist kompatibel zu C<? super B>, wenn B kompatibel ist zu (abgeleitet ist von) A Bei Wildcard-Typen mit unterer Begrenzung sind Lesezugriffe, die von den Typ-Argumenten abhängen, grund- sätzlich nicht zulässig. (Ausnahme : Lesen von Object-Objekten ist immer zulässig). Die aus einem – konkret vorhandenen – Basisklassen-Stack auslesbaren Objekte können nicht als Objekte eines abgeleiteten Typs (der die Begrenzung darstellt) betrachtet werden. Schreibzugriffe dagegen sind erlaubt. Z.B. kann ein Number-Objekt immer auf einen – konkret vorhandenen – Object-Stack abgelegt werden (oder ein Integer-Objekt auf einem Number-Stack)
? extends Referenz-Typ
? super Referenz-Typ
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 300 – 00 – TH – 04 ------------------------------------------------------------------------------------
Programmieren in Java
Kapitel 3
3. Elementare Programmfunktionalitäten 3.1. Zugriff zu Programmparametern 3.2. Standard-Ein-und-Ausgabe (Konsolen-E/A) 3.3. Interaktion mit dem Laufzeitsystem 3.4. Exceptions 3.5. Dateizugriff
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 311 – 00 – TH – 01 -----------------------------------------------------------------------------------
Zugriff zu Programmparametern in Java •••• Programparameter (Kommandozeilenparameter)
◇ Einem Programm können i.a. beim Aufruf Parameter übergeben werden. � Programmparameter
◇ Diese werden beim Aufruf aus der Kommandozeile durch Blanks getrennt an den eigentlichen Programmaufruf angehängt. � Kommandozeilenparameter Bei Java-Programmen werden sie nach dem Namen der Start-Klasse angegeben.
◇ Beispiel : java Echo Sie tanzte nur einen Sommer Kommandozeilenparameter sind : Sie tanzte nur einen Sommer •••• Zugriff im Programm
◇ Die Programmparameter (ohne Namen der Startklasse !) werden in einem String-Array zusammengefasst. Eine Referenz auf dieses Array wird der main()-Methode der Startklasse als Parameter übergeben.
◇ Die main()-Methode der Startklasse muß daher mit einem Parameter (Argument) vom Typ String[] definiert werden : public static void main(String[] args) { // ... }
◇ Innerhalb der main()-Methode stehen damit die Programmparameter als Komponenten des String-Arrays args zur Verfügung.
◇ Die Anzahl der Programmparameter (= Länge des String-Arrays) ist ermittelbar mittels args.length. •••• Beispiel : Beispiel eines Programm-Aufrufs :
// Echo.java class Echo { public static void main(String[] args) { for (int i=0; i<args.length; i++) System.out.println("Parameter "+ i + " : " + args[i]); } }
E:\java\fhm\ee\vorl>java Echo Sie tanzte nur einen Sommer
Parameter 0 : Sie Parameter 1 : tanzte Parameter 2 : nur Parameter 3 : einen Parameter 4 : Sommer E:\java\fhm\ee\vorl>
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 321 – 00 – TH – 04 ------------------------------------------------------------------------------------
Standard-Ein- und Ausgabe in Java (1) •••• Grundsätzliches zum I/O-Model von Java
◇ Eine Programm-Ein- und Ausgabe findet üblicherweise über Dateien und/oder Geräte statt.
◇ Java betrachtet sowohl Geräte als auch Dateien grundsätzlich als sequentielle Folge von Bytes (Byte-Stream). Da Java Zeichen und Strings im Unicode darstellt, bietet die Sprache auch die Möglichkeit Textdateien/Text-Geräte als sequentielle Folge von Unicode-Zeichen (Unicode-Stream) zu interpretieren.
◇ Programmintern wird eine Datei bzw ein Gerät durch ein Objekt einer Stream-Klasse repräsentiert.
◇ Es gibt zahlreiche verschiedene Stream-Klassen, die jeweils unterschiedliche Eigenschaften modellieren. Alle Stream-Klassen sind im Package java.io enthalten.
◇ Vier abstrakte Klassen sind Basisklassen aller übrigen Stream-Klassen :
▻ InputStream Basisklasse für Klassen zum byteweisen Lesen (Lesen von Byte-Streams)
▻▻▻▻ Reader Basisklasse für Klassen zum zeichenweisen Lesen (Lesen von Unicode-Zeichen-Streams)
▻ OutputStream Basisklasse für Klassen zum byteweisen Schreiben (Schreiben in Byte-Streams)
▻ Writer Basisklasse für Klasse zum zeichenweisen Schreiben (Schreiben in Unicode-Zeichen-Streams) Diese Klassen definieren jeweils ein generelles Interface zur Verwendung der Objekte der entsprechenden abgeleiteten Klassen.
◇ Konverter-Klassen (Brücken-Klassen) erlauben einen Übergang zwischen Byte-Streams und Unicode-Zeichen- Streams :
▻ InputStreamReader (abgeleitet von Reader) Klasse zum zeichenweisen Lesen aus Byte-Streams
▻ OutputStreamWriter (abgeleitet von Writer) Klasse zum zeichenweisen Schreiben in Byte-Streams •••• Standard-Ein- und Ausgabe-Objekte
◇ Für die Standard-Eingabe, die Standard-Ausgabe und die Standard-Fehlerausgabe werden für jedes Programm automatisch Stream-Objekte angelegt, d.h. die entsprechenden Streams (üblicherweise Tastatur und Bildschirm des Konsolengeräts) sind implizit geöffnet. Aus historischen Gründen handelt es sich hierbei um Byte-Stream-Objekte.
◇ Referenzen auf diese Stream-Objekte stehen als öffentliche statische Datenkomponenten der – nicht instanzierbaren – Klasse System (im Package java.lang) zur Verfügung :
▻ public static final InputStream in Standard-Eingabe-Objekt
▻ public static final PrintStream out Standard-Ausgabe-Objekt
▻ public static final PrintStream err Standard-Fehlerausgabe-Objekt Die Klasse PrintStream ist eine von OutputStream – indirekt – abgeleitete Klasse. Sie ermöglicht das Schreiben von Werten der einfachen Datentypen und von Objekten beliebiger Klassen (nach Umwandlung in eine String-Repräsentation) sowie direkt von Strings in einen Byte-Stream. Hierfür stellt sie die mehrfach überladenen Funktionen print() und println() (nicht explizit formatierbare Ausgabe) sowie die Methode printf() (formatierte Ausgabe) zur Verfügung.
◇ Ab dem JDK 6.0 kann als Alternative für den Zugriff zum Konsolengerät auch ein vordefiniertes Objekt der Klasse Console eingesetzt werden.
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 322 – 00 – TH – 03 ------------------------------------------------------------------------------------
Standard-Ein- und Ausgabe in Java (2)
•••• Schreiben in die Standard-Ausgabe und Standard-Fehlerausgabe
◇ Mittels der für die Standard-Stream-Objekte
▻ System.out (Standard-Ausgabe, Klasse PrintStream)
▻ System.err (Standard-Fehlerausgabe, Klasse PrintStream) aufgerufenen Methoden
▻ public void print(...)
▻ public void println(...)
▻ public PrintStream printf(String form, Object... args) (ab dem JDK 5.0)
▻ public PrintStream format(String form, Object... args) (ab dem JDK 5.0)
◇ Die Methoden print() und println() haben jeweils einen Parameter und ermöglichen die Ausgabe - von boolean-, char-, double-, float-, int- und long-Werten - von char-Arrays - von Strings (Objekte der Klasse String) - sowie der String-Repräsentation (Methode toString()) von Objekten beliebiger Klassen
◇ Die Methode println() ergänzt die Ausgabe um ein Zeilenendezeichen. Sie lässt sich auch ohne Parameter aufrufen. In diesem Fall bewirkt sie lediglich einen Übergang in eine neue Zeile.
◇ Beispiel :
◇ Die Anwendung der String-Konkatenation in Verbindung mit der automatischen Umwandlung von beliebigen Datenwerten und Objekten in eine String-Repräsentation bei ihrem Auftritt in Konkatenations-Aus drücken (Methode toString()) erlaubt die Ausgabe mehrerer Werte/Objekte mit einem Methodenaufruf. Achtung : Der +-Operator (Konkatenation, Addition) ist links-rechts-assoziativ. Damit bei mehrfacher Konkatenation tatsächlich der richtige Gesamtstring entsteht, muss bei der ersten (am weitesten links stehenden) Verknüpfungsoperation wenigstens ein String beteiligt sein. Beispiel :
class StdOutDemo1 { public static void main(String[] args) { boolean b = true; char c = 'Z'; int i = 399127; long l = 124L; float f = 2.25E-2f; double d = 0.0/0.0; String s = "Hallo !"; StdOutDemo1 sod = new StdOutDemo1(); System.out.print(b); System.out.println(); System.out.println(c); System.out.println(i); System.out.println(l); System.out.println(f); System.out.println(d); System.out.println(s); System.out.println(sod); } }
class StdOutDemo2 { public static void main(String[] args) { System.out.println(1 + '+' + 1 + " ergibt " + 2); System.out.println(1 + "+" + 1 + " ergibt " + 2); }
}
true Z 399127 124 0.0225 NaN Hallo ! StdOutDemo1@eee36c
Ausgabe :
45 ergibt 2 1+1 ergibt 2
Ausgabe :
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 323 – 01 – TH – 04 ------------------------------------------------------------------------------------
Standard-Ein- und Ausgabe in Java (3 - 1)
•••• Formatierte Ausgabe (ab dem JDK 5.0)
◇ Mittels der PrintStream-Methoden public PrintStream printf(String form, Object... args); public PrintStream format(String form, Object... args); Rückgabewert bei beiden Methoden : aktuelles PrintStream-Objekt
◇ Beide Methoden sind in der Wirkung identisch. Sie ermöglichen eine C-ähnliche formatierte Ausgabe
◇ Der erste Parameter form ist der Format-String. Er enthält – analog zum Format-String der C-Funktion printf() – die einzelnen Formatangaben (format specifier) für die auszugebenden Werte/Objekte. Durch die Formatangaben wird auch der Typ bzw die Darstellungsart der Ausgabe-Werte festgelegt Zusätzlich kann der Format-String weiteren Text enthalten, der direkt ausgegeben wird.
◇ Die zweite Parameter-Angabe Object... args bedeutet, dass eine beliebige Anzahl (auch keine) weiterer Parameter beliebigen Referenz-Typs folgen darf. Diese Parameter (Argumente) legen die Werte fest, die entsprechend des jeweils spezifizierten Formats auszugeben sind. Für jede Formatangabe muss ein passendes Argument übergeben werden. Die Typen dieser Argumente müssen zu den entsprechenden Angaben im Format-String passen. Überflüssige Argumente werden ignoriert Als Parameter können auch Werte einfacher Datentypen auftreten, da sie mittels Autoboxing automatisch in Objekte der zugehörigen Wrapper-Klassen umgewandelt werden.
◇ Syntax der Formatangaben (vereinfacht) : % [flags][width][.precision]conversion
▻ conversion (Konvertierungszeichen) legt die Formatierungsart und/oder den Typ der Ausgabe fest und schließt eine Formatangabe ab Die wichtigsten Konvertierungszeichen sind : Bei einem Großbuchstaben als Konvertierungszeichen werden alle Buchstaben als Großbuchstaben ausgegeben
▻ flags (Steuerflags) modifizieren das Ausgabeformat, sie können gegebenenfalls miteinander kombiniert werden Die wichtigsten Steuerflags sind :
▻ width (Ausgabefeldbreite) legt die minimale Ausgabefeldbreite fest ▻ precision (Genauigkeit) legt i.a. die maximale Ausgabefeldbreite fest, bei Gleitpunktzahlen jedoch die Anzahl der Nachpunktstellen (Ausnahme : beim Konvertierungszeichen g bzw G wird die Gesamtzahl der Ziffern festgelegt), bei Strings : Anzahl der auszugebenden Zeichen des Strings
◇ Nichtzulässige Zeichen in einer Formatangabe sowie fehlende oder zu einer Formatangabe nicht-kompatible Argu- mente führen zum Werfen einer IllegalFormatException.
b oder B logischer Wert d ganzzahliger Wert in Dezimaldarstellung o ganzzahliger Wert in Oktaldarstellung x oder X ganzzahliger Wert in Sedezimaldarstellung c oder C Unicode-Zeichen e oder E Gleitpunkt-Wert in Exponentialdarstellung f Gleitpunkt-Wert in Dezimalbruchdarstellung g oder G Gleitpunkt-Wert in Dezimalbruchdarstellung oder Exponentialdarstellung (abhängig von Wert und Genauigkeit) s oder S String (der String, der durch die jeweilige Methode toString() erzeugt wird) n Zeilenendezeichen
- linksbündige Ausgabe + auch positive Werte werden mit Vorzeichen ausgegeben (nur für Zahlen anwendbar) 0 Ausgabe führender Nullen (nur für Zahlen anwendbar) ' ' (Blank) Ausgabe positiver Werte mit führendem Blank (nur für Zahlen anwendbar)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 323 – 02 – TH – 02 ------------------------------------------------------------------------------------
Standard-Ein- und Ausgabe in Java (3 - 2) •••• Ergänzende Anmerkungen zur formatierten Ausgabe (ab dem JDK 5.0)
◇ Es existieren noch weitere Möglichkeiten der Formatierung (insbesondere auch für Datums- und Zeitdarstellungen). Genauere Informationen können der API-Dokumentation zur Klasse Formatter (Package java.util) entnommen werden.
◇ Zur Erzeugung von formatierten Ausgaben kann auch die Klasse Formatter eingesetzt werden : Mit Objekten dieser Klasse ist es u.a. möglich
▻ formatierte Ausgaben direkt in Dateien oder OutputStream- sowie PrintStream-Objekten vorzunehmen
▻ formatierte Strings zu erzeugen (als Objekte der Klassen StringBuffer oder StringBuilder). Diese Strings können dann explizit ausgegeben (print() oder println()) bzw in Dateien geschrieben werden. •••• Demonstrationsprogramm zur formatierten Ausgabe : Ausgabe des Programms :
// FormOutpDemo1.java // Demonstrationsprogramm zur formatierten Ausgabe public class FormOutpDemo1 { void show() { int anz = 10; double summe = 99.98765; float anteil = 0.00005432f; String type = "Airbus A-380"; System.out.println("0123456789012345678901234567890123456789"); System.out.printf("Anzahl : %5d Summe : %8.3e\n", anz, summe); System.out.format("Anzahl : %5d Summe : %8.3e\n", anz, summe); System.out.printf("Anzahl : %-5d Summe : %8.3f\n", anz, summe); System.out.printf("Anzahl : %0+5d Summe : %08.3f\n", anz, summe); System.out.printf("Anteil : % .4g\n", anteil); System.out.printf("Anteil : %.4E\n", anteil); System.out.printf("Anteil : %.4f\n", anteil); System.out.printf("Typ : %s\n", type); System.out.printf("Typ : %15s\n", type); System.out.printf("Typ : %5s\n", type); System.out.printf("Typ : %5.6S\n", type); System.out.printf("Typ : %8.6s\n", type); System.out.printf("%B\n", true); } public static void main(String[] args) { FormOutpDemo1 demo = new FormOutpDemo1(); demo.show(); }
0123456789012345678901234567890123456789 Anzahl : 10 Summe : 9.999e+01 Anzahl : 10 Summe : 9.999e+01 Anzahl : 10 Summe : 99,988 Anzahl : +0010 Summe : 0099,988 Anteil : 5.432e-05 Anteil : 5.4320E-05 Anteil : 0,0001 Typ : Airbus A-380 Typ : Airbus A-380 Typ : Airbus A-380 Typ : AIRBUS Typ : Airbus TRUE
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 324 – 00 – TH – 04 -----------------------------------------------------------------------------------
Standard-Ein- und Ausgabe in Java (4) •••• Lesen aus der Standard-Eingabe
◇ Das für die Standard-Eingabe definierte Stream-Objekt System.in steht als Instanz der Klasse InputStream zur Verfügung. Diese Klasse besitzt zum Einlesen lediglich die mehrfach überladene Methode read(), mit der nur einzelne Bytes oder eine Gruppe von Bytes (Byte-Array) eingelesen werden können.
◇ Üblicherweise soll von der Standard-Eingabe aber Text eingelesen werden, der vom Programm entweder als Wert eines einfachen Datentyps oder direkt als String interpretiert und verwendet werden soll. D.h. also, es müssen Zeichenfolgen (Datentyp char) und nicht Bytefolgen (Datentyp Byte) eingelesen werden.
◇ Der über System.in erhältliche Byte-Stream muß also in einen Unicode-Stream umgewandelt werden. Diese erfolgt mittels eines Objekts der Klasse InputStreamReader. Dem Konstruktor zur Erzeugung dieses Objekts ist das zugrundeliegende InputStream-Objekt, hier also System.in als Parameter zu übergeben. Die Klasse InputStreamReader erlaubt mittels der überladenen Methode read() das Einlesen von Einzel- zeichen bzw Zeichen-Arrays. Einlesen von Einzelzeichen : public int read() throws IOException Funktionswert : gelesenes Zeichen bzw –1 bei Eingabeende
◇ Um Strings einlesen zu können, wird ein BufferedReader-Objekt benötigt. Dieses lässt sich unter Verwendung des InputStreamReader-Objekts, das dem Konstruktor als Parameter zu übergeben ist, erzeugen (Der Kon- struktor der Klasse BufferedReader benötigt ein Reader-Objekt als Parameter, die Klasse InputStreamReader ist von Reader abgeleitet). Die Klasse BufferedReader stellt neben der überladenen Methode read() zum Einlesen von Einzelzeichen und Zeichen-Arrays eine Methode zum zeilenweisen Lesen zur Verfügung : public String readLine() throws IOException Funktionswert : eingelesene Zeile als String-Objekt (ohne Zeilenende-Zeichen) bzw null wenn das Eingabe- Ende (EOF, Dateiende) erreicht ist. Bei der Anwendung dieser Methode (wie auch aller anderen Lese-Methoden) ist zu berücksichtigen, dass bei Auftritt eines I/O-Fehlers, eine Exception vom Typ IOException geworfen wird. Diese ist entweder in der aufrufenden Funktion zu fangen oder von dieser weiterzuwerfen.
◇ Darstellung als Klassendiagramm :
◇ Beispiel :
// EchoLines.java import java.io.*; class EchoLines { public static void main(String[] args) throws IOException { BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); String line; while ((line=stdin.readLine()) != null) System.out.println(line); } }
BufferedReader
+read():int +readLine():String
InputStreamReader
+read():int
InputStream
+read():int
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 325 – 00 – TH – 04 ------------------------------------------------------------------------------------
Standard-Ein- und Ausgabe in Java (5) •••• Lesen aus der Standard-Eingabe, Forts.
◇ Zum Einlesen von Werten der einfachen Datentypen muß der eingelesene String entsprechend dem Datentyp inter- pretiert und in die interne Wertedarstellung umgewandelt werden. Hierfür stehen entsprechende statische Methoden der jeweiligen Wrapper-Klassen zur Verfügung :
▻ Klasse Byte : public static byte parseByte(String str) throws NumberFormatException;
▻ Klasse Short : public static short parseShort(String str) throws NumberFormatException;
▻ Klasse Integer : public static int parseInt(String str) throws NumberFormatException;
▻ Klasse Long : public static long parseLong(String str) throws NumberFormatException;
▻ Klasse Float : public static float parseFloat(String str) throws NumberFormatException;
▻ Klasse Double : public static double parseDouble(String str) throws NumberFormatException; Diese Methoden liefern die interne Darstellung des durch den Parameter str repräsentierten Werts des jeweiligen Typs als Funktionswert zurück. Sie erzeugen eine Exception vom Typ NumberFormatException, wenn str keinen entsprechenden Zahlenwert darstellt.
◇ Zur Umwandlung eines Strings in einen boolean-Wert müssen zwei Methoden der Wrapper-Klasse Boolean eingesetzt werden :
▻ Klasse Boolean : public static Boolean valueOf(String str); Diese Methode erzeugt ein Boolean-Objekt, das den Wert true repräsentiert, wenn der Parameter str gleich dem String "true" ist , wobei Groß-/Kleinschreibung ignoriert wird ("True" oder "TRUE" z.B. führen ebenfalls zum Wert true). Für jeden anderen Wert von str repräsentiert das erzeugte Boolean-Objekt den Wert false.
▻ Klasse Boolean : public boolean booleanValue(); Diese Methode gibt den durch ein Boolean-Objekt repräsentierten boolean-Wert zurück.
◇ Beispiel :
◇ Eine alternative, flexiblere und einfachere Möglichkeit zum Einlesen von Werten einfacher Datentypen bietet die mit dem JDK 5.0 eingeführte Klasse Scanner
import java.io.*; class StdInpDemo { public static void main(String[] args) throws IOException { int a, b; BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Wert von a ? "); a = Integer.parseInt(stdin.readLine()); System.out.print("Wert von b ? "); b = Integer.parseInt(stdin.readLine()); System.out.println("a+b = " + (a+b)); System.out.print("Boolean-Wert ? "); String s = stdin.readLine(); boolean bw = Boolean.valueOf(s).booleanValue(); System.out.println("Eingabe war : " + bw); } }
Wert von a ? 213 Wert von b ? 421 a+b = 634 Boolean-Wert ? True Eingabe war : true
Beispiel für Ein- und Ausgabe des Programms :
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 326 – 01 – TH – 03 ------------------------------------------------------------------------------------
Die Klasse Scanner in Java (1) •••• Allgemeines zur Klasse Scanner
◇ Bestandteil des Packages java.util, ab dem JDK 5.0 vorhanden
◇ Objekte der Klasse Scanner dienen zum Zergliedern und Interpretieren von Zeichenfolgen.
◇ Die von Scanner-Objekten bearbeitbaren Zeichenfolgen können aus unterschiedlichen Eingabe-Quellen stammen (Dateien, sonstige Eingabe-Streams wie z.B. die Standard-Eingabe, Strings). Die jeweilige Quelle muss beim Erzeugen eines Scanner-Objekts festgelegt werden.
◇ Scanner-Objekte zerlegen ihre Eingabe-Zeichenfolge in Teil-Abschnitte (token). Die Zeichen(-muster), die als Trennzeichen zwischen den Abschnitten interpretiert werden (delimiter pattern), lassen sich konfigurieren. Defaultmässig werden Whitespace-Character verwendet.
◇ Die einzelnen Teil-Abschnitte stehen als Strings zur Verfügung und können als Werte eines einfachen Datentyps interpretiert und in die dem jeweiligen Typ entsprechende interne Darstellung umgewandelt werden.
◇ Damit lassen sich Scanner-Objekte sehr elegant zum Einlesen von Werten der einfachen Datentypen aus der Standard-Eingabe einsetzen, insbesondere auch dann, wenn in einer Eingabezeile mehrere einzulesende Werte enthalten sind. •••• Konstruktoren der Klasse Scanner (Auswahl)
•••• Memberfunktionen der Klasse Scanner (Auswahl)
public Scanner(File source) Erzeugung eines Scanner-Objekts, dessen Eingabe-Quelle die durch source spezifizierte Datei ist
public Scanner(Readable source) Erzeugung eines Scanner-Objekts, dessen Eingabe-Quelle das durch source spezifizierte Objekt ist. Dieses Objekt muss das Interface Readable implementieren
public Scanner(InputStream source) Erzeugung eines Scanner-Objekts, dessen Eingabe-Quelle das durch source spezifizierte InputStream-Objekt ist
public Scanner(String source) Erzeugung eines Scanner-Objekts, dessen Eingabe-Quelle der durch source spezifizierte String ist.
public String nextLine() Rückgabe des Rests der aktuellen Eingabe-Zeile
public boolean hasNextLine() Überprüfung, ob eine weitere Eingabe-Zeile vorhanden ist, wenn ja true
public String next() Rückgabe des nächsten Teil-Abschnitts (token) der Eingabe-Zeichenfolge
public boolean hasNext() Überprüfung ob ein weiterer Teil-Abschnitt vorhanden ist, wenn ja true public byte nextByte()
public short nextShort() Interpretation des nächsten Teil-Abschnitts der Eingabe-Zeichenfolge als Wert des jeweiligen Typs und Rückgabe der internen Darstellung dieses public int nextInt() Wertes Jede der Funktionen wirft eine Exception vom Typ public long nextLong() InputMismatchException,
wenn der Teil-Abschnitt sich nicht als Wert des jeweiligen Typs interpretieren public float nextFloat() lässt (boolean-Werten können mit Gross- und/oder Kleinbuchstaben darge- stellt werden) public double nextDouble() public boolean nextBoolean()
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 326 – 02 – TH – 01 ------------------------------------------------------------------------------------
Die Klasse Scanner in Java (2) •••• Demonstrationsbeispiele zur Klasse Scanner
◇ Programm EchoLinesScanDemo
◇ Programm StdInpScanDemo
◇ Beispiel für die Ein- und Ausgabe des Programms StdInpScanDemo
// EchoLinesScanDemo.java // Echo der von der Standard-Eingabe eingelesenen Zeilen in die Standard-Ausgabe // Verwendung der Klase Scanner import java.util.*; public class EchoLinesScanDemo { public static void main(String[] args) { Scanner scan = new Scanner(System.in); while (scan.hasNextLine()) System.out.println(scan.nextLine()); } }
// StdInpScanDemo.java // Demonstrationsprogramm zum Einlesen von der Standard-Eingabe // Verwendung der Klasse Scanner import java.util.*; public class StdInpScanDemo { public static void main(String[] args) { int a, b; Scanner scan = new Scanner(System.in); System.out.print("Zwei Integer-Werte a und b ? "); a = scan.nextInt(); b = scan.nextInt(); System.out.println("a+b = " + (a + b)); System.out.print("Boolean-Wert ? "); boolean bw = scan.nextBoolean(); System.out.println("Eingabe war : " + bw); } }
Zwei Integer-Werte a und b ? 12 25 a+b = 37 Boolean-Wert ? FalsE Eingabe war : false
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 327 – 01 – TH – 04 ------------------------------------------------------------------------------------
Die Klasse Console in Java (1) •••• Allgemeines zur Klasse Console
◇ Bestandteil des Packages java.io, ab dem JDK 6.0 vorhanden
◇ Die Klasse stellt Methoden zum Zugriff zum Konsolengerät zur Verfügung. Ein Objekt dieser Klasse bildet eine – allerdings nicht immer vorhandene – Alternative zur Verwendung der Standard- Ein-/Ausgabe-Stream-Objekte.
◇ Die Klasse verfügt über keinen öffentlichen Konstruktor. Sie kann also nicht explizit instanziert werden. Vielmehr erfolgt eine implizite Instanzierung als Singleton durch die JVM, falls mit dieser ein Konsolengerät verbunden ist. Dieses ist u.a. immer dann der Fall, wenn die JVM aus einer Kommandozeile heraus ohne Umleitung der Standard-Ein- und Ausgabe gestartet wird. Das Konsolengerät wird dann typischerweise durch die Tastatur (Standard-Eingabe) und den Bildschirm (Standard-Ausgabe) gebildet. Wenn die JVM dagegen aus einem anderen Prozess (z.B. Hintergrundprozess oder IDE) heraus gestartet wird, ist mit ihr i.a. kein Konsolengerät verbunden.
◇ Das gegebenenfalls vorhandene einzige Objekt der Klasse Console kann mittels der statischen Methode der Klasse System public static Console console() ermittelt werden. Falls kein Console-Objekt existiert, liefert die Methode null zurück.
◇ Die Klasse Console stellt im wesentlichen die folgenden Funktionalitäten zur Verfügung :
▻ Formatierte Ausgabe
▻ zeilenweises Einlesen
▻ Einlesen von Passwörtern (mit ausgeschalteter Echo-Ausgabe)
▻ Ermittlung der vom Console-Objekt verwendeten Stream-Objekte für die Aus- bzw Eingabe. Bei diesen Objekten handelt es sich um Zeichen-Stream-Objekte. Über sie bestehen weitere Möglichkeiten zur Aus- bzw Eingabe. Anmerkung : Die Standard-Stream-Objekten sind dagegen Byte-Stream-Objekte.
◇ Die Schreib- und Lese-Methoden der Klasse sind synchronisiert, d.h. sie sind für den Einsatz in Multi-Thread- anwendungen geeignet.
◇ Die Lese-Methoden geben als Funktionswert null zurück, wenn das Ende des Konsolen-Eingabe-Streams erreicht ist (Eingabe von Ctrl-Z unter Windows bzw Ctrl-D unter Linux/Unix). Wenn anschliessend weitere Zeichen eingegeben werden, können sie mit weiteren Lese-Operationen eingelesen weden. •••• Memberfunktionen der Klasse Console zur Ermittlung der E/A-Stream-Objekte
◇ Mittels der von der Klasse Reader implementierten Methoden lassen sich über dieses Eingabe-Stream-Objekt - Einzelzeichen (Methode read()) sowie - Zeichenfolgen (mehrere Methoden read(...), s. API-Dokumentation) einlesen Das Einlesen von Zeichenfolgen über Zeilengrenzen hinweg ist dabei nicht möglich. Da die Klasse Reader das Interface Readable implementiert, lässt sich das Eingabe-Stream-Obekt als Quelle für Scanner-Objekte einsetzen.
◇ Die Klasse PrintWriter stellt u.a. die gleichen Methoden print(...), println(...), printf(...) und format(...) zur Verfügung wie die Klasse PrintStream. Damit lassen sich über das Ausgabe-Stream- Objekt die gleichen Ausgabe-Operationen wie über die Standard-Ausgabe-Stream-Objekte (System.out und System.err) realisieren.
public Reader reader() Ermittlung des mit der Konsole verknüpften Eingabe-Stream-Objekts. (Objekt der Klasse Reader) � Funktionswert
public PrintWriter writer() Ermittlung des mit der Konsole verknüpften Ausgabe-Stream-Objekts. (Objekt der Klasse PrintWriter) � Funktionswert
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 327 – 02 – TH – 02 ------------------------------------------------------------------------------------
Die Klasse Console in Java (2) •••• Memberfunktionen der Klasse Console zur Ein- und Ausgabe
◇
▻ formatierte Ausgabe in den Ausgabe-Stream der Konsole
▻ Beide Methoden besitzen die gleiche Funktionalität
▻ Parameter : form Formatstring, enthält die Formatangaben für die auszugebenden Werte/Objekte Syntax der Formatangaben s. Methode printf(...) der Klasse PrintStream args Referenzen auf die auszugebenden Werte/Objekte
▻ Funktionswert : aktuelles Console-Objekt
◇
▻ unmittelbare Ausgabe (Flush) des Buffers des Konsolen-Ausgabe-Streams
◇
▻ Lesen der nächsten Zeile aus dem Konsolen-Eingabe-Stream
▻ Funktionswert : gelesene Zeile bzw null (wenn am Zeilenende gelesen wird) Das Zeilenende-Zeichen wird nicht mit zurückgegeben
◇
▻ Ausgabe eines formatierten Prompts in den Konsolen-Ausgabe-Stream, anschliessend Lesen der nächsten Zeile aus dem Konsolen-Eingabe-Stream
▻ Parameter : Festlegung des Prompts, s. Parameter der Methode printf(...) (bzw format(...))
▻ Funktionswert : gelesene Zeile bzw null (wenn am Zeilenende gelesen wird) Das Zeilenende-Zeichen wird nicht mit zurückgegeben
◇
▻ Lesen eines Passworts aus dem Konsolen-Eingabe-Stream mit ausgeschalteter Echo-Ausgabe
▻ Funktionswert : Gelesenes Passwort (in einem char-Array) bzw null (wenn am Zeilenende gelesen wird) Ein Zeilenende-Zeichen wird nicht mit zurückgegeben
▻ Anmerkung : Da die Methode das gelesene Passwort als char-Array und nicht als String-Objekt zurückgibt, kann es unmittelbar nach Verwendung im Speicher überschrieben werden
◇
▻ Ausgabe eines formatierten Prompts in den Konsolen-Ausgabe-Stream, anschliessend Lesen eines Passworts aus dem Konsolen-Eingabe-Stream mit ausgeschalteter Echo-Ausgabe
▻ Parameter : Festlegung des Prompts, s. Parameter der Methode printf(...) (bzw format(...))
▻ Funktionswert : Gelesenes Passwort (in einem char-Array) bzw null (wenn am Zeilenende gelesen wird) Ein Zeilenende-Zeichen wird nicht mit zurückgegeben
▻ Anmerkung : Da die Methode das gelesene Passwort als char-Array und nicht als String-Objekt zurückgibt, kann es unmittelbar nach Verwendung im Speicher überschrieben werden
public void flush()
public String readLine()
public String readLine(String form, Object... args)
public Console printf(String form, Object... args) public Console format(String form, Object... args)
public char[] readPassword()
public char[] readPassword(String form, Object... args)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 327 – 03 – TH – 01 ------------------------------------------------------------------------------------
Demonstrationsprogramm zur Klasse Console in Java •••• Programm ConsoleDemo
// ConsoleDemo.java // Demo-Programm zur Klasse Console import java.io.*; import java.util.*; public class ConsoleDemo { public static void main(String[] args) throws IOException { Console con = System.console(); if (con == null) { System.err.println("JVM besitzt keine Console -- Schade"); } else { System.err.println("JVM besitzt eine Console"); con.printf("%s\n", "Das ist gut"); char[] altPass = con.readPassword("%s ", "altes Passwort ?"); con.printf("Die folgende Ausgabe sollte nicht erfolgen :\n"); con.printf("Das Passwort lautet : %s \n", new String(altPass)); con.writer().print("Das Passwort lautet : "); con.writer().println(altPass); if (!verifyPasswd(altPass)) con.printf("keine Berechtigung\n"); else { char[] neuPass1; char[] neuPass2; do { neuPass1 = con.readPassword("neues Passwort ? "); neuPass2 = con.readPassword("neues Passwort wiederholen : "); } while (!Arrays.equals(neuPass1, neuPass2)); changePasswd(neuPass1); Arrays.fill(neuPass1, ' '); Arrays.fill(neuPass2, ' '); } Arrays.fill(altPass, ' '); } System.out.print("Geben Sie einen beliebigen String ein : "); BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String s = stdin.readLine(); System.out.println(s); } static void changePasswd(char[] pw) { System.out.println("Passwort geaendert !"); } static boolean verifyPasswd(char[] pw) { return true; } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 331 – 00 – TH – 04 ------------------------------------------------------------------------------------
Interaktion mit dem Laufzeitsystem in Java (1)
•••• Die Klasse System
◇ Die Klasse System ist eine nicht-instanzierbare Utility-Klasse (Package java.lang), die einen Zugriff zu einigen Systemeigenschaften ermöglicht. Im wesentlichen stellt sie zur Verfügung :
▻ die Standard-Ein- und Ausgabe-Objekte (öffentliche statische Datenkomponenten)
▻ eine statische Methode zur Ermittlung des Konsolen-Objekts, falls vorhanden (ab JDK 1.6)
▻ statische Methoden zum Ermitteln (und Ändern) der System-Umgebung ("System Properties")
▻ statische Methoden zum Zugriff zu den aktuellen Environment-Variablen des Betriebssystems (ab JDK 1.5)
▻ statische Methoden zum Setzen und Ermitteln des im System installierten SecurityManager-Objekts
▻ statische Utility-Methoden (z.B. zur Ermittlung der aktuellen Zeit, Teilkopieren von Arrays)
▻ einige statische Methoden, die zum aktuellen Runtime-Objekt zugreifen (Aufruf gleichnamiger Methoden) : Der Aufruf System.method() ist äquivalent zu Runtime.getRuntime().method() •••• Ermittlung der aktuellen Zeit
◇ Hierzu dient die statische Methode der Klasse System : public static long currentTimeMillis(); Rückgabewert : Vergangene Zeit seit dem 1.1.1970 UTC, Mitternacht in Millisekunden
◇ Zur Decodierung dieser Zeit in ihre üblicherweise vom Menschen verwendeten Komponenten (Zeit und Datum) kann die Bibliotheks-Klasse Date (Package java.util) eingesetzt werden :
▻ Erzeugung eines Date-Objektes, dessen Konstruktor der von currentTimeMillis() zurückgegebene Wert als Parameter übergeben wird.
▻ Aufruf der Methode public String toString() für dieses Date-Objekt. Der von dieser Methode als Funktionswert erzeugte String enthält die Zeit (und Datum) in folgender Form : dow mon dd hh:mm:ss zzz yyyy
◇ Beispiel :
import java.util.Date; class ActTime { public static void main(String[] args) { Date act = new Date(System.currentTimeMillis()); System.out.println("aktuelle Zeit : " + act.toString()); } }
aktuelle Zeit : Wed Aug 08 19:38:30 CEST 2007
public static void gc() expliziter Aufruf des Garbage Collectors
public static expliziter Aufruf der finalize()-Methoden aller void runFinalization() zur Vernichtung anstehenden Objekte
public static Laden der durch libname spezifizierten dynam.Library void loadLibrary(String libname) (native Code) Die Zuordnung zwischen Library, Library-Ort, und Library-Dateiname ist systemabhängig
public static Laden einer dynam. Library (native Code), die durch den absoluten void load(String filepath) Dateipfad filepath referiert wird.
public static void exit(int status) Beendigung der aktuell laufenden JVM (u. damit des Programms). Der Parameter status ist der Programm-Exit-Code
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 332 – 00 – TH – 03 -----------------------------------------------------------------------------------
Interaktion mit dem Laufzeitsystem in Java (2) •••• System-Umgebung (System Properties)
◇ Die System-Umgebung besteht aus System-Eigenschaften (System Properties). Diese werden z. Tl von Standard- Bibliotheks-Klassen benutzt. Sie können aber auch in eigenen Klassen verwendet werden.
◇ Eine System Property hat einen Namen und einen Wert. Der Name ist ein String, der durch jeweils einen Punkt in mehrere Abschnitte unterteilt sein kann. Der Wert ist ebenfalls ein String. •••• Änderung der System-Umgebung
◇ Für jede JVM existiert ein Satz von Standard System Properties.
◇ Zusätzlich können benutzerdefinierte System Properties beim Programm- (JVM-) Start festgelegt werden. Hierzu dient die –D Option beim Aufruf der JVM. Beispiel : java –DLabor.aktuell=LSW ActTime Hierdurch wird die System Property mit dem Namen "Labor.aktuell" und dem Wert "LSW" zusätzlich gesetzt.
◇ Darüberhinaus können weitere System Properties auch während des Programmlaufs gesetzt werden, vorausgesetzt das SecurityManager-Objekt erlaubt es. Zum Setzen (und Ändern) einer System Property existiert in der Klasse System die statische Methode
▻ Die Methode setzt eine System Property mit dem Namen key auf den Wert val. Als Funktionswert gibt die Methode den zuvor gesetzt gewesenen Wert der System Property bzw – falls diese noch nicht existiert hat – null zurück. Beispiel : System.setProperty("Labor.aktuell", "LSW"); •••• Ermittlung der System-Umgebung
◇ Properties werden in Objekten der Klasse Properties (Package java.util) gespeichert. Für die Standard System Properties wird beim Start der JVM ein entsprechendes Objekt angelegt. (System- Properties-Objekt). Zu ihm kann über die Klasse System zugegriffen werden. Benutzerdefinierte System Properties (sowohl bei Programmstart festgelegte, als auch im Programm gesetzte) werden in dieses Objekt eingefügt. Ein Benutzer kann in einem Programm darüberhinaus weitere Properties-Objekte anlegen.
◇ Statische Methoden der Klasse System zum Zugriff zum System-Properties-Objekt :
▻ Funktionswert : das System-Properties-Objekt
▻ Funktionswert : der Wert der System Property mit dem Namen key, bzw null, falls Property nicht existiert
◇ Sämtliche in einem Properties-Objekt enthaltenen Properties (Name/Wert-Paare) lassen sich mittels der folgenden Methode der Klasse Properties über ein PrintStream-Objekt ausgeben : public void list(PrintStream out);
public static String setProperty(String key, String val)
public static Properties getProperties()
public static String getProperty(String key)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 333 – 00 – TH – 03 ------------------------------------------------------------------------------------
Interaktion mit dem Laufzeitsystem in Java (3) •••• Beispielprogramm zur Ausgabe der System Properties in die Standard-Ausgabe
import java.util.Properties; class SysProps { public static void main(String[] args) { System.getProperties().list(System.out); } }
-- listing properties -- java.runtime.name=Java(TM) SE Runtime Environment sun.boot.library.path=C:\Programme\Java\jre1.6.0\bin java.vm.version=1.6.0-b105 java.vm.vendor=Sun Microsystems Inc. java.vendor.url=http://java.sun.com/ path.separator=; java.vm.name=Java HotSpot(TM) Client VM file.encoding.pkg=sun.io user.country=DE sun.java.launcher=SUN_STANDARD sun.os.patch.level=Service Pack 2 java.vm.specification.name=Java Virtual Machine Specification user.dir=E:\Java\Vorlesung\elemprogfunc java.runtime.version=1.6.0-b105 java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment java.endorsed.dirs=C:\Programme\Java\jre1.6.0\lib\endorsed os.arch=x86 java.io.tmpdir=C:\DOKUME~1\thomas\LOKALE~1\Temp\ line.separator= java.vm.specification.vendor=Sun Microsystems Inc. user.variant= os.name=Windows XP sun.jnu.encoding=Cp1252 java.library.path=C:\WINDOWS\system32;.;C:\WINDOWS\Sun\... java.specification.name=Java Platform API Specification java.class.version=50.0 sun.management.compiler=HotSpot Client Compiler os.version=5.1 user.home=C:\Dokumente und Einstellungen\thomas user.timezone= java.awt.printerjob=sun.awt.windows.WPrinterJob file.encoding=Cp1252 java.specification.version=1.6 user.name=thomas java.class.path=.;C:\Programme\Java\jre1.6.0\lib\ext\... java.vm.specification.version=1.0 sun.arch.data.model=32 java.home=C:\Programme\Java\jre1.6.0 java.specification.vendor=Sun Microsystems Inc. user.language=de awt.toolkit=sun.awt.windows.WToolkit java.vm.info=mixed mode, sharing java.version=1.6.0 java.ext.dirs=C:\Programme\Java\jre1.6.0\lib\ext;C:... sun.boot.class.path=C:\Programme\Java\jre1.6.0\lib\resour... java.vendor=Sun Microsystems Inc. file.separator=\ java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport... sun.cpu.endian=little sun.io.unicode.encoding=UnicodeLittle sun.desktop=windows sun.cpu.isalist=
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 334 – 00 – TH – 01 -----------------------------------------------------------------------------------
Interaktion mit dem Laufzeitsystem in Java (4) •••• Zugriff zu den Environment-Variablen des Betriebssystems
◇ Ab dem JDK 5.0 kann in Java-Programmen wieder zu den vom Betriebssystem verwalteten Environment-Variablen zugegriffen werden.
◇ Eine Environment-Variable besitzt – wie eine System Property – einen Namen und hat einen Wert. Sowohl Name als auch Wert sind jeweils ein String. � Jede Environment-Variabale bildet ein String-Paar.
◇ Mit den folgenden statischen Methoden der Klasse System kann zu dem bei der Programmabarbeitung aktuellen Environment zugegriffen werden :
▻ Ermittlung aller aktuellen Environment-Variablen. Funktionswert : - String-String-Map , die die Environment-Variablen enthält. Falls das Betriebssystem keine Environment-Variablen unterstützt, ist die zurückgegebene Map leer. Eine Map ist ein assoziativer Container, der Schlüssel (key) –Werte (value)-Paare speichert. Als Schlüssel dient hier der Name einer Environment-Variablen, der Wert ist der Wert dieser Variablen
▻ Ermittlung des Werts der Environment-Variablen mit dem Namen name Funktionswert : - Wert der Environment-Variablen - bzw null, wenn keine Environment-Variable mit dem Namen name existiert Falls ein Security Manager installiert ist, wird er von beiden Funktionen befragt, ob der Zugriff zum Environment zulässig ist. Bei Unzulässigkeit wird eine SecurityException geworfen.
◇ Beispielprogramm zum Zugriff zu den Environment-Variablen Auflistung aller Environmentvariablen (Name = Wert) in die Standard-Ausgabe
public static Map<String, String> getenv()
public static String getenv(String name)
// GetEnv.java // Ermittlung des aktuellen Environments import java.util.*; public class GetEnv { public static void main(String[] args) { Map<String, String> env = System.getenv(); Set<String> keys = env.keySet(); for (String name : keys) System.out.println(name + " = " + System.getenv(name)); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 335 – 00 – TH – 01 ------------------------------------------------------------------------------------
Die Klasse Runtime in Java (1)
•••• Grundsätzliches
◇ Die Klasse Runtime befindet sich im Package java.lang.
◇ Jede Java-Applikation besitzt genau ein Objekt dieser Klasse. Es wird beim Start der JVM automatisch erzeugt. Dieses Objekt bildet ein Interface zwischen der Java-Applikation und der Laufzeitumgebung der ausführenden JVM.
◇ Zur Ermittlung des aktuellen Runtime-Objekts dient die statischen Methode der Klasse Runtime : static Runtime getRuntime() � Runtime.getRuntime() liefert das mit der aktuellen Java-Applikation assoziierte Runtime-Objekt.
◇ Eine explizite Instanzierung der Klasse ist nicht möglich.
◇ Die Klasse Runtime stellt Funktionalitäten in folgenden Bereichen zur Verfügung :
▻ Information über Systemresourcem der JVM (Prozessoranzahl, Arbeitsspeicher)
▻ expliziter Aufruf des Garbage Collectors
▻ Ausführung externer Programme in Kindprozessen
▻ Laden dynamischer Bibliotheken (nativer Code)
▻ Debug-Unterstützung
▻ Beendigung (shutdown) der JVM •••• Information über Systemresourcen der JVM
◇ Hierfür dienen die folgenden Methoden der Klasse Runtime
◇ Demonstrationsbeispiel :
public class ResInfo { public static void main(String[] args) { Runtime rt = Runtime.getRuntime(); System.out.println("Einige Systemresourcen der JVM :"); System.out.println("Anzahl Prozessoren : " + rt.availableProcessors()); System.out.println("gesamter Arbeitsspeicher : " + rt.totalMemory() + " Bytes"); System.out.println("freier Arbeitsspeicher : " + rt.freeMemory() + " Bytes"); System.out.println("maximaler Arbeitsspeicher : " + rt.maxMemory() + " Bytes"); } }
Einige Systemresourcen der JVM : Anzahl Prozessoren : 2 gesamter Arbeitsspeicher : 5177344 Bytes freier Arbeitsspeicher : 4997096 Bytes maximaler Arbeitsspeicher : 66650112 Bytes
public int availableProcessors() Rückgabe der Anzahl Prozessoren, die der JVM zur Verfügung stehen
public long freeMemory() Ermittlung des freien der JVM zur Verfügung stehenden Arbeitsspeichers, Funktionswert = freier Arbeitsspeicher in Bytes
public long totalMemory() Ermittlung des gesamten der JVM zur Verfügung stehenden Arbeits- peichers, Funktionswert = gesamter Arbeitsspeicher in Bytes
public long maxMemory() Ermittlung der maximalen Arbeitspeichergröße, die die JVM zu nutzen versuchen wird (in Bytes) Falls keine obere Grenze existiert, Rückgabe von Long.MAX_VALUE
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 336 – 00 – TH – 02 ------------------------------------------------------------------------------------
Die Klasse Runtime in Java (2) •••• Ausführung externer Programme in Kindprozessen
◇ Die Erzeugung von Kindprozessen, die ein anzugebendes Programm ausführen, wird durch mehrere überladene Methoden mit dem Namen exec ermöglicht.
◇ Alle exec-Methoden geben bei Erfolg als Funktionswert ein Objekt der Klasse Process zurück. Dieses Objekt repräsentiert den neu erzeugten Kindprozeß. Es ermöglicht dem Elternprozeß hinsichtlich bestimmter Aspekte eine Interaktion mit dem erzeugten Kindprozeß (z.B. Warten auf Kindprozeßende, Ermittlung des Return- Codes des Kindprozesses, Abbruch des Kindprozesses)
◇ Beim Auftreten von Fehlern werfen die exec-Methoden entsprechende Exceptions. So werfen alle exec-Methoden beim Auftreten eines I/O-Fehlers (z.B. Programmdatei nicht gefunden) eine IOException.
◇ Falls ein Security Manager installiert ist (ein SecurityManager-Objekt existiert), überprüft dieser, ob die Aus- führung des angegebenen Programms zulässig ist. Bei Unzulässigkeit wird eine SecurityException geworfen.
◇ Überblick über die exec-Methoden (Auswahl) : Wird kein Environment angegeben (Methoden mit nur einem Parameter bzw envp == null) so wird dem im Kindprozess ausgeführten Programm das Environment des Elternprozesses übergeben Es existieren zwei weitere exec-Methoden (3 Parameter), mit denen für den neu erzeugten Kindprozeß explizit das Arbeitsdirectory festgelegt werden kann. Wird für den entsprechenden Parameter null übergeben so erbt – wie bei den o.a. exec-Methoden – der Kindprozeß das Arbeitsdirectory des Elternprozesses.
◇ Einfaches Demonstrationsbeispiel :
import java.io.*; class ExecDemo { public static void main(String[] args) throws IOException { String[] cmd = null; if (args.length>0) cmd = args; else { cmd = new String[1]; cmd[0]= "calc"; } Runtime.getRuntime().exec(cmd); } }
public Process exec(String cmd) Ausführung des durch cmd referierten Programms in einem neu throws IOException erzeugten Kindprozeß
public Process exec(String[] cmdarr) Ausführung des durch cmdarr[0] referierten Programms in einem throws IOException neu erzeugten Kindprozeß. Die übrigen Elemente von cmdarr (ab Index 1) werden dem Programm als Programmparameter übergeben
public Process exec(String cmd, Ausführung des durch cmd referierten Programms in einem neu String[] envp) erzeugten Kindprozeß throws IOException envp referiert das dem Programm zu übergebende Environment
public Process exec(String[] cmdarr, Ausführung des durch cmdarr[0] referierten Programms in einem String[] envp) neu erzeugten Kindprozeß. Die übrigen Elemente von cmdarr throws IOException (ab Index 1) werden dem Programm als Programmparameter übergeben envp referiert das dem Programm zu übergebende Environment
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 341 – 00 – TH – 03 -----------------------------------------------------------------------------------
Exceptions in Java (1) •••• Prinzip des Exception Handlings
◇ Java stellt – wie auch C++ – einen speziellen Mechanismus zur Behandlung von Ausnahmesituationen (Fehlerfällen,
Exceptions), die während der Programmausführung auftreten können, zur Verfügung ⇒ Exception Handling
◇ Ausnahmesituationen in diesem Sinne sind Fehler, oder sonstige unerwünschte Sonderfälle (z.B. Dateizugriffsfehler, Verletzung von Array-Grenzen, Datenformatfehler usw), die im normalen Programmablauf nicht auftreten sollten, aber auftreten können. Exception Handling ist kein Mechanismus zur Behandlung von externen oder internen Interrupts.
◇ Exception Handling trennt den Code, der Fehler verursachen kann, von dem Code, der einen aufgetretenen Fehler behandelt. Dadurch kann der eigentliche den normalen Programmablauf steuernde (produktive) Code frei gehalten werden von einer ständigen Überprüfung auf den Auftritt von Fehlern und Sonderfällen sowie der Reaktion auf diese. Dies trägt erheblich zur Klarheit und Übersichtlichkeit des Codes bei.
◇ Code (z.B. eine Methode einer Bibliotheksklasse), der eine Ausnahmesituation entdeckt, wirft eine Exception, die dann von einem anderen Code-Teil, dem Exception-Handler gefangen wird. Im Exception-Handler findet die Reaktion auf die (Bearbeitung der) Ausnahmesituation statt. Diese kann der Fehlerart sowie der jeweiligen spezifischen Programmsituation angepasst werden. Z.B. kann eine Fehlermeldung ausgegeben werden und anschliessend das Programm fortgesetzt oder beendet werden. Oder es kann versucht werden, die Fehler- ursache zu beseitigen und das Programm dann fortzusetzen.
◇ Exceptions werden als Objekte behandelt. Sie enthalten Informationen über die Fehlerursache und stellen Methoden zum Zugriff zu diesen zur Verfügung. Werfen einer Exception (throwing) bedeutet das Erzeugen eines Objekts einer Exception-Klasse und die anschlies- sende Suche eines passenden Exception-Handlers. Wird ein derartiger Handler gefunden, wird ihm das Exception-Objekt (genauer eine Referenz darauf) übergeben (� Fangen der Exception, catching). Dem Handler stehen damit die im Exception-Objekt enthaltenen Informationen zur Auswertung zur Verfügung.
◇ Exception Handling wird in Java wesentlich umfangreicher und strikter als in C++ angewendet :
▻ In der Standard-Bibliothek sind zahlreiche Exception-Klassen definiert. Sie bilden eine über mehrere Pakete verteilte Klassenhierarchie, die die Klasse Throwable (von Object abgeleitet, Paket java.lang) als Wurzelklasse besitzt. Im Konstruktor einer derartigen Klasse wird i.a. die Exception-Ursache bzw eine Kurzbeschreibung der Exception durch einen String (fest codiert oder als Parameter übergeben) festgelegt.
▻ Viele Methoden vieler Bibliotheksklassen werfen Exceptions.
▻ Java erzwingt, dass geworfene Exceptions gefangen werden müssen. Existiert in einem Benutzerprogramm kein geeigneter Exception-Handler, so werden sie von einem in der JVM angesiedelten Standard-Handler behandelt, der Informationen über die Exception in die Standard-Ausgabe ausgibt und anschliessend das Programm (genauer den aktuellen Thread) beendet.
▻ Ein Benutzer kann jederzeit eigene Exception-Klassen definieren. Dies kann sinnvoll sein, wenn spezielle Fehler- fälle gesondert von anderen behandelt werden sollen (z.B. "Division durch Null" als Spezialfall einer ArithmeticException). Eine beutzerdefinierte Exception-Klasse muß von einer der Standard-Bibliotheks-Exception-Klassen abgeleitet sein
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 342 – 00 – TH – 03 -----------------------------------------------------------------------------------
Exceptions in Java (2) •••• Hierarchie der Bibliotheks-Exception-Klassen
◇ Alle Exception-Klassen sind – direkt oder indirekt – von der Klasse Throwable abgeleitet.
◇ Die Klasse Throwable (Paket java.lang) ist eine direkte Unterklasse von Object.
◇ Überblick über den Anfang der Hierarchie :
◇ Exceptions der Klasse Error sowie der davon abgeleiteten Klassen kennzeichnen ernsthafte Systemfehler, die normalerweise nicht auftreten sollten, aber prinzipiell jederzeit auftreten können. Ein normales Benutzerprogramm kann auf derartige Exceptions i.a. nicht sinnvoll reagieren und sollte sie deswegen auch nicht fangen. Vielmehr sollten sie immer vom Default-Exception-Handler der JVM behandelt werden.
◇ Exceptions der Klasse RuntimeException sowie der davon abgeleiteten Klassen können ebenfalls prinzipiell an beliebiger Stelle während des Programmablaufs auftreten. I.a. liegt ihre Ursache in einem logischen Programmier- fehler (z.B. Division durch 0 oder unzulässiger Array-Index). Eine vernünftige Reaktion zur Laufzeit ist i.a. nicht möglich. Derartige Fehler sollten i.a. im Programm-Code korrigiert werden. Ein Benutzerprogramm kann diese Exceptions behandeln (d.h. geeignete Exception-Handler bereitstellen), muß es aber nicht. Im letzteren Fall erfolgt wiederum eine Behandlung durch den Default-Handler der JVM.
◇ Exceptions aller übrigen Klassen (z.B. IOException) repräsentieren Fehler, mit denen man prinzipiell rechnen muß (z.B. Datei ist nicht vorhanden) und die deswegen auch in irgendeiner Weise behandelt werden müssen. Für diese Exceptions schreibt Java eine "catch-or-declare"-Erfordernis vor. Sie müssen von der Funktion, in der sie geworfen werden, entweder gefangen oder von ihr als weiter-werfbar deklariert werden. Andererseits darf eine Funktion nur solche Exceptions dieser Klassen werfen, die sie auch deklariert hat. Das Einhalten dieser Erfordernis kann vom Compiler überprüft werden. Sie werden daher als geprüfte (checked) Exceptions bezeichnet.
◇ Exceptions der Klassen Error und RuntimeException sowie der davon abgeleiteten Klassen sind dagegen ungeprüfte (unchecked) Exceptions. Sie können jederzeit geworfen werden, ohne daß sie von der entsprechenden Funktion deklariert werden müssen. Für sie gilt die "catch-or-declare"-Erfordernis nicht, sie dürfen aber deklariert werden
Throwable
Error Exception
weitere Error-Klassen
VirtualMachineError RuntimeException IOException
ArithmeticException FileNotFoundException
weitere Exception-
Klassen
weitere RuntimeException-
Klassen
weitere IOException-
Klassen
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 343 – 00 – TH – 02 -----------------------------------------------------------------------------------
Exceptions in Java (3)
•••• Die Klasse Throwable
◇ Die direkt von der Klasse Object abgeleitete Klasse Throwable (Paket java.lang) ist Basisklasse aller Exception-Klassen.
◇ Sie definiert ein allgemeines Interface für den Zugriff zu den Exception-Objekten aller Exception-Klassen Die vier wichtigsten Methoden dieses Interfaces sind :
▻ public String getMessage(); Diese Methode gibt den bei der Exception-Objekt-Erzeugung gespeicherten Ursachen- bzw Kurzbeschreibungs- String als Funktionswert zurück, bzw null, falls kein derartiger String gespeichert wurde. ▻ public String toString(); Diese Methode erzeugt einen String, der aus dem vollqualifizierten Namen der tatsächlichen Klasse des Exception- Objekts besteht, gegebenenfalls (falls getMessage() einen Wert !=null zurückgibt) gefolgt von ": " und dem Rückgabewert von getMessage(). ▻ public void printStackTrace(); Diese Methode gibt den Funktionswert von toString() gefolgt von dem Aufruf-Stack der Funktion, in der die Exception ursprünglich geworfen wurde, in die Standard-Fehler-Ausgabe (System.err) aus. ▻ public void printStackTrace(PrintStream s); Diese Methode gibt den Funktionswert von toString() gefolgt von dem Aufruf-Stack der Funktion, in der die Exception ursprünglich geworfen wurde, in den durch s referierten Print-Stream aus. •••• Deklaration werfbarer Exceptions (throws-Klausel)
◇ Die von einer Funktion werfbaren geprüften Exceptions müssen von dieser deklariert werden. Werfbare ungeprüfte Exceptions können, müssen aber nicht deklariert werden.
◇ Die Deklaration erfolgt durch eine im Funktionskopf nach der Parameterliste anzugebende throws-Klausel. Die throws-Klausel besteht aus dem Schlüsselwort throws, gefolgt von einer durch Kommata getrennten Auflistung von Exception-Klassen
◇ Syntax :
◇ Beispiel : public String liesEtwas(String dname) throws FileNotFoundException, EOFException { // ... } •••• Werfen einer Exception
◇ Mittels einer throw-Anweisung. Nach dem Schlüsselwort throw ist eine Referenz auf das zu werfende Exception-Objekt anzugeben. Diese Referenz kann
▻ der Wert eines new-Ausdrucks sein (neu erzeugtes Exception-Objekt)
▻ die einem Exception-Handler übergebene Objekt-Referenz sein ("Weiterwerfen" der Exception)
◇ Syntax :
◇ Beispiel : throw new ArithmeticException("Nenner ist Null");
Exception-Klasse throws
,
throw Exception-Objekt-Referenz ;
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 344 – 00 – TH – 02 ------------------------------------------------------------------------------------
Exceptions in Java (4)
•••• Die try-Anweisung
◇ Sie ermöglicht das Fangen von Exceptions.
◇ Eine try-Anweisung besteht i.a. aus drei Teilen :
▻ dem try-Block
▻ einem oder mehreren catch-Blöcken
▻ einem finally-Block Entweder die catch-Blöcke oder der finally-Block dürfen auch fehlen, aber nicht beides.
◇ Syntax :
◇ Der try-Block enthält den eigentlichen produktiven Code, der auf den Auftritt von Exceptions überwacht wird. Er wird solange ausgeführt, bis entweder durch eine der Anweisungen eine Exception (direkt durch eine throw-Anwei- sung oder indirekt durch eine aufgerufene Funktion) geworfen wird oder alle Anweisungen erfolgreich abgearbeitet worden sind. Beim Auftritt einer Exception wird der try-Block sofort verlassen und nach einem Exception-Handler gesucht, der die Exception fangen kann.
◇ Die catch-Blöcke bilden die Exception-Handler. Jeder catch-Block ist zuständig für das Fangen von Exceptions einer bestimmten Klasse bzw deren Unterklassen. Die von einem catch-Block fangbare Exception-Klasse ist in seinem Kopf – analog zur Parameter-Deklaration von Funktionen – angegeben. Da Objekte (genauer Objekt-Referenzen) einer Klasse zuweisungskompatibel zu Variablen einer Basisklasse sind, können auch Exceptions aller Klassen, die von der deklarierten Klasse abgeleitet sind, gefangen werden. Die Suche nach einem "passenden" Exception-Handler erfolgt in der Reihenfolge ihrer Angabe im Quellcode. Wird ein Exception-Handler gefunden, der die geworfene Exception fangen kann, wird das Programm mit seiner Abarbeitung fortgesetzt. Dabei wird die Exception wie ein formaler Funktionsparameter an den Handler übergeben. Wird kein "passender" Exception-Handler gefunden, wird die Suche in der jeweils nächsten umfassenden try-An- weisung (gegebenenfalls in der aufrufenden Funktion) fortgesetzt. Bleibt auch das erfolglos, wird der Default-Exception-Handler der JVM ausgeführt und das Programm beendet.
◇ Der finally-Block enthält Code, der immer ausgeführt wird, unabhängig davon, wie die try-Anweisung verlassen wird, ob durch reguläre Beendigung des try-Blocks oder durch Werfen einer gefangenen oder nicht gefangenen Exception. Die Ausführung des finally-Blocks erfolgt unmittelbar vor Verlassen des try-Blocks bzw – beim Fangen einer Exception – vor Verlassen des entsprechenden catch-Blocks. Die Ausführung erfolgt auch dann, wenn try- bzw catch-Block mit einer return-Anweisung verlassen werden. Der finally-Block wird insbesondere verwendet, um Aufräumarbeiten durchzuführen und sicherzustellen, dass belegte System-Resourcen (z.B. geöffnete Dateien) freigegeben werden
try Anweisung { }
catch ( Exception-Klasse Name )
Anweisung { }
finally Anweisung { }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 345 – 00 – TH – 01 -----------------------------------------------------------------------------------
Exceptions in Java (5)
•••• Demonstrationsprogramm zu Exceptions
// ExceptDemo.java import java.io.*; class ExceptDemo { public void func1() { try { System.out.println("in func1() : Aufruf von func2()"); func2(); System.out.println("normales Ende von try in func1()!"); return; } finally { System.out.println("func1() verlassen !"); } } public void func2() { try { System.out.println("in func2() : Aufruf von func3()"); func3(); System.out.println("normales Ende von try in func2()!"); return; } catch (RuntimeException e) { System.out.print("Exception-Handler in func2() : "); System.out.println(e.getMessage()); } finally { System.out.println("func2() verlassen !"); } } public void func3() { try { System.out.println("in func3() : Exception wird geworfen"); throw new RuntimeException("Demo-Exception !"); } catch (ArithmeticException e) { System.out.print("Exception-Handler in func3() : "); System.out.println(e.getMessage()); } finally { System.out.println("func3() verlassen !"); } } public static void main(String[] args) { ExceptDemo ed = new ExceptDemo(); ed.func1(); } }
in func1() : Aufruf von func2() in func2() : Aufruf von func3() in func3() : Exception wird geworfen func3() verlassen ! Exception-Handler in func2() : Demo-Exception ! func2() verlassen ! normales Ende von try in func1()! func1() verlassen !
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 351 – 00 – TH – 01 -----------------------------------------------------------------------------------
Dateizugriff in Java (1)
•••• Überblick
◇ Java behandelt Dateien als sequentielle Folge von Bytes (Byte-Streams)
◇ In der IO-Bibliothek (Package java.io) sind zahlreiche Klassen definiert, die das Arbeiten mit Dateien unter- stützen. Die wichtigsten dieser Klassen sind :
▻ die File-Stream-Klassen zum sequentiellen Zugriff • FileInputStream (byteweises Lesen) • FileOutputStream (byteweises Schreiben) • FileReader (zeichenweises Lesen) • FileWriter (zeichenweises Schreiben)
▻ eine Klasse zum wahlfreien Zugriff (Lesen und Schreiben) • RandomAccessFile
▻ Klassen für den Zugriff zum Dateisystem • FileDescriptor • File
◇ Auszugsweises Klassendiagramm : Anmerkungen :
▻ Das Diagramm beschränkt sich auf die Datei-Eingabe-Stream-Klassen (FileInputStream, FileReader).
▻ Für die Datei-Ausgabe-Stream-Klassen (FileOutputStream, FileWriter) bestehen analoge Ableitungs- und Nutzungsbeziehungen. Deren – direkte oder indirekte – Basisklassen sind OutputStream bzw Writer.
▻ Die IO-Bibliothek enthält eine Reihe weiterer – hier nicht aufgeführter – Streamklassen, die zumeist von InputStream oder Reader (bzw OutputStream oder Writer) direkt oder indirekt abgeleitet sind.
FilterInputStream
InputStream
BufferedInputStream DataInputStream
InputStreamReader
FileDescriptor
FileReader FileInputStream RandomAccessFile
File
Reader
BufferedReader
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 352 – 01 – TH – 04 ------------------------------------------------------------------------------------
Dateizugriff in Java (2-1)
•••• Die Klasse File
◇ Objekte dieser Klasse repräsentieren Zugriffspfade (zu Dateien bzw Directories) im Dateisystem.
◇ Wesentliche Funktionalitäten :
▻ Speicherung eines Datei- bzw Directory-Zugriffspfades in einer abstrakten system-unabhängigen Darstellung, sowie Bereitstellung von Informationen über denselben
▻ Ermittlung diverser Eigenschaften einer repräsentierten Datei (bzw eines repräsentierten Directories)
▻ Manipulation von Dateisystem-Einträgen (Erzeugen, Löschen, Änderung bestimmter Eigenschaften)
◇ Der repräsentierte Zugriffspfad kann durch einen absoluten oder einen relativen Pfadnamen bezeichnet sein. Ein relativer Pfadname wird immer auf das aktuelle Arbeitsdirectory des Users bezogen (Wert der System Property user.dir). Typischerweise handelt es sich hierbei um das Directory, aus dem die JVM gestartet wurde.
◇ Zugriffspfade bestehen aus :
▻ einem optionalen betriebsystem-abhängigen Prefix-String (z.B. "D:\\", "E:" oder "/")
▻ einer Folge von keinem oder mehr Namen-Strings, die jeweils ein Directory bzw (nur der letzte String) eine Datei bezeichnen. Die einzelnen Namen-Strings sind durch ein betriebssystem-abhängiges Trennzeichen separiert. Das betriebssystem-abhängige Trennzeichen ist der Wert der System Property file.separator.
Es steht auch als öffentliche statische Datenkomponente der Klasse File zur Verfügung : public static final char separatorChar; bzw public static final String separator; (String mit einem Zeichen)
◇ Konstruktoren :
▻ public File(String path) Erzeugung eines neuen File-Objekts, das den Zugriffspfad path repräsentiert. Falls path==null ist, wird eine NullPointerException geworfen.
▻ public File(String dirName, String name) Erzeugung eines neuen File-Objekts, das den aus dirName und name gebildeten Zugriffspfad repräsentiert. (Eintrag name im Directory dirName). Äquivalent zu : File(dirName + File.separator + name) Falls name==null ist, wird eine NullPointerException geworfen.
▻ public File(File fileDir, String name) Erzeugung eines neuen File-Objekts, das den Zugriffspfad repräsentiert, der aus dem Eintrag name in dem durch fileDir repräsentierten Directory gebildet wird, Äquivalent zu : File(fileDir.getPath(), name) Falls name==null ist, wird eine NullPointerException geworfen.
▻ public File(URI uri) Erzeugung eines neuen File-Objekts, dessen repräsentierter Zugriffspfad durch Konvertierung des Unified Resource Identifiers erhalten wird, der durch das URI-Objekt uri repräsentiert wird. Es muß sich hierbei um den Resource Identifier einer Datei handeln (Beginn mit file:) Falls uri==null ist, wird eine NullPointerException geworfen. Falls uri keine Datei repräsentiert, wird eine IllegalArgumentException geworfen.
◇ Der durch ein File-Objekt repräsentierte Zugriffspfad muß nicht einen tatsächlich existierenden Dateisystem-Eintrag referieren. Zur Überprüfung, ob ein entsprechender Dateisystem-Eintrag vorhanden ist, d.h. durch das File-Objekt also tat- sächlich eine Datei oder ein Directory repräsentiert wird, dient die Memberfunktion
▻ public boolean exists() Funktionswert : true, wenn der Eintrag existiert, false, wenn der Eintrag nicht existiert
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 352 – 02 – TH – 03 ------------------------------------------------------------------------------------
Dateizugriff in Java (2-2)
•••• Die Klasse File, Forts.
◇ Methoden zum Erzeugen neuer Dateisystem-Einträge
▻ public boolean createNewFile() throws IOException Diese Methode erzeugt eine neue leere Datei mit dem vom aktuellen File-Objekt repräsentierten Zugriffspfad, falls noch keine Datei mit diesem Zugriffspfad existiert. Funktionswert : true, falls die Datei erzeugt werden konnte false, falls eine Datei mit dem Zugriffspfad bereits existiert hat. Falls ein I/O-Fehler auftritt, wird eine IOException geworfen.
▻ public boolean mkdir() Diese Methode erzeugt eine neues Directory mit dem vom aktuellen File-Objekt repräsentierten Zugriffspfad Funktionswert : true, falls das Directory erzeugt werden konnte, andernfalls false
▻ public boolean mkdirs() Diese Methode erzeugt ein neues Directory mit dem vom aktuellen File-Objekt repräsentierten Zugriffspfad sowie gegebenenfalls alle noch nicht existierenden Eltern-Directories. Funktionswert : true, falls das Directory und alle noch nicht existierenden Eltern-Directories erzeugt werden konnten false, falls das Directory nicht erzeugt werden konnte. Anm. : In diesem Fall können durchaus einige Eltern-Directories erzeugt worden sein.
◇ Methoden zur Ermittlung von Informationen über Dateisystem-Einträge
▻ public String getAbsolutePath() Rückgabe des absoluten Pfadnamens
▻ public String getCanonicalPath() Rückgabe des kanonischen Pfadnamens
▻ public long length() Rückgabe der Dateilänge, bei Directories undefinierter Funktionswert
▻ public boolean isDirectory() true, wenn Eintrag existiert und Directory ist, sonst false
▻ public boolean isFile() true, wenn Eintrag existiert und normale Datei ist, sonst false
▻ public boolean isHidden() true, wenn Eintrag existiert und verborgen ist, sonst false
▻ public boolean canWrite() true, wenn Eintrag existiert und geändert werden kann, sonst false
▻ public boolean canRead() true, wenn Eintrag existiert und gelesen werden kann, sonst false
▻ public String[] list() Wenn Eintrag ein Directory ist : Rückgabe einer Auflistung aller in ihm enthaltenen Einträge als String-Array (ausser "." und "..") Wenn Eintrag kein Directory ist : Rückgabe von null
▻ public File[] listFiles() Wie list(), nur Rückgabe der Einträge als File-Array
◇ Methoden zur Veränderung von Dateisystem-Einträgen
▻ public boolean renameTo(File newPath) Umbenennen / Verschieben des aktuell repräsentierten Dateisystem-Eintrags. Der Dateisystem-Eintrag wird anschliessend durch das File-Objekt newPath repräsentiert. Der vom aktuellen Objekt bisher repräsentierte Eintrag existiert anschliessend nicht mehr. Funktionswert : true, falls Umbenennen / Verschieben erfolgreich war, andernfalls false Falls newPath==null ist, wird eine NullPointerException geworfen.
▻ public boolean delete() Löschen des aktuell repräsentierten Dateisystem-Eintrags. Ein zu löschendes Directory muss es leer sein. Funktionswert : true, falls erfolgreich gelöscht werden konnte, andernfalls false
◇ Es existieren noch zahlreiche weiterer Methoden.
◇ Alle Methoden, die zu einer System Property zugreifen oder einen Zugriff zum Dateisystem bewirken, werfen eine SecurityException, wenn der Zugriff nicht zulässig ist.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 352 – 03 – TH – 01 -----------------------------------------------------------------------------------
Dateizugriff in Java (2-3)
•••• Demoprogramm 1 zur Klasse File Beispiele für Programmaufruf und -ausgabe
// TestRename.java import java.io.*; public class TestRename { public static void main(String[] args) throws IOException { if (args.length<=1) System.out.println("Angabe von Quell- und Zielpfad erforderlich"); else { File fil = new File(args[0]); if (!fil.exists()) { System.out.print("Quellpfad \"" + args[0] + "\" existiert nicht"); if (fil.createNewFile()) System.out.println(" --> neu erzeugt"); else System.out.println(" --> Erzeugung nicht möglich"); } if (fil.exists()) { System.out.println("Dateigroesse : " + fil.length() + " Bytes"); File neufil = new File(args[1]); boolean succ = fil.renameTo(neufil); if (!succ) System.out.println("rename nicht erfolgreich"); else { System.out.println("rename erfolgreich"); System.out.print("alter Pfad : " + fil); if (!fil.exists()) System.out.println(" existiert nicht mehr"); System.out.println("neuer Pfad : " + neufil); } } } }
E:\Java\fhm\ee\vorl\fileacc>java TestRename ftest2.txt ftest2.dat Dateigroesse : 33 Bytes rename erfolgreich alter Pfad : ftest2.txt existiert nicht mehr neuer Pfad : ftest2.dat
E:\Java\fhm\ee\vorl\fileacc>java TestRename ftest2.txt ftest2.dat Quellpfad "ftest2.txt" existiert nicht --> neu erzeugt Dateigroesse : 0 Bytes rename nicht erfolgreich
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 352 – 04 – TH – 03 ------------------------------------------------------------------------------------
Dateizugriff in Java (2-4)
•••• Demoprogramm 2 zur Klasse File Beispiele für Programmaufruf und -ausgabe
// ListDir.java import java.io.*; public class ListDir { public static void main(String[] args) { try { if (args.length<=0) throw new IOException("Programmparameter (Directory-Pfad) fehlt !"); File dir = new File(args[0]); if (!dir.exists()) throw new IOException("\"" + args[0] + "\" existiert nicht !"); if (!dir.isDirectory()) throw new IOException("\"" + dir.getAbsolutePath() + "\" ist kein Directory!"); String[] entries = dir.list(); System.out.println("Inhalt des Directories \"" + dir.getAbsolutePath() + "\" :"); for (int i=0; i<entries.length; i++) System.out.println(entries[i]); } catch (IOException ex) { System.out.println(ex.getMessage()); } } }
E:\Java\fhm\ee\vorl\fileacc>java ListDir Programmparameter (Directory-Pfad) fehlt !
E:\Java\fhm\ee\vorl\fileacc>java ListDir meindir "meindir" existiert nicht !
E:\Java\fhm\ee\vorl\fileacc>java ListDir ftestdir "E:\Java\fhm\ee\vorl\fileacc\ftestdir" ist kein Directory!
E:\Java\fhm\ee\vorl\fileacc>java ListDir . Inhalt des Directories "E:\Java\fhm\ee\vorl\fileacc\." : FileTest1.java FileTest1.class ftest.txt ftest2.dat TestRename.java TestRename.class ftest1.dat ftest3.txt testren1.txt testren2.txt ftestdir ListDir.java ListDir.class
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 353 – 00 – TH – 04 ------------------------------------------------------------------------------------
Dateizugriff in Java (3)
•••• Die Klasse FileDescriptor
◇ Objekte dieser Klasse bilden ein Handle zu der vom jeweiligen Betriebssystem für eine geöffnete Datei (allgemeiner : für einen geöffneten Stream) angelegten Verwaltungsstruktur.
◇ Jedes Objekt, über dem ein Zugriff zu einer Datei erfolgt (Objekt einer File-Stream-Klasse bzw der Klasse RandomAccessFile) ist mit einem FileDescriptor-Objekt assoziiert. Dieses stellt die Verbindung zur Dateiverwaltung auf der Betriebssystemebene her.
◇ Ein FileDescriptor-Objekt wird üblicherweise implizit beim Anlegen eines Objekts für den Dateizugriff und dem damit verbundenen Öffnen der Datei erzeugt. Ein explizites Erzeugen eines FileDescriptor-Objekts ist weder üblich noch sinnvoll. Mit dem zur Verfügung stehenden öffentlichen parameterlosen Konstruktor kann nur ein ungültiges Objekt, das an keine geöffnete Datei gebunden ist, erzeugt werden.
◇ Für Objekte der Klassen FileInputStream, FileOutputStream und RandomAccessFile (nicht jedoch der Klassen FileReader und FileWriter) kann mit der jeweiligen Methode getFD() das mit ihnen assoziierte FileDescriptor-Objekt ermittelt werden.
◇ Bei der Erzeugung eines neuen File-Stream-Objekts kann auch ein existierendes FileDescriptor-Objekt verwendet werden. Das neue File-Stream-Objekt referiert dann dieselbe Datei wie das File-Stream-Objekt, das das FileDescriptor-Objekt geliefert hat. Damit kann über zwei (oder mehr) Stream-Objekte zur selben Datei zuge- griffen werden.
◇ Methoden der Klasse FileDescriptor
▻ Überprüfung, ob das FileDescriptor-Objekt gültig, d.h. an eine geöffnete Datei gebunden ist. Funktionswert : true, falls das Objekt an eine geöffnete Datei gebunden ist, andernfalls false
▻ Synchronisation aller System-Buffer, die Daten für die referierte Datei enthalten, mit dem physikalischen Speichermedium. Die Funktion kehrt erst dann zurück, wenn alle relevanten Daten auf das physikalische Medium geschrieben worden sind. Die Methode sorgt nicht für das Herausschreiben von Buffern, die in dem Anwendungsprogramm verwendet werden (z.B. von einem BufferedOutputStream-Objekt). Diese müssen gegebenenfalls zuvor an das Betriebssystem übergeben werden (mittels der jeweiligen Stream-Methode flush()). Wenn eine Synchronisation der System-Buffer mit dem physikalischen Speichermedium nicht sichergestellt werden kann, wird eine SyncFailedException geworfen.
◇ Die Klasse FileDscriptor stellt Handle zu den Standard-Streams als öffentliche statische Datenkompo- nenten zur Verfügung Normalerweise werden diese jedoch nicht direkt von User-Code verwendet sondern indirekt über die durch die Klasse System bereitgestellten Standard-Stream-Objekte.
▻ public static final FileDescriptor in Handle zum Standard-Eingabe-Stream
▻ public static final FileDescriptor out Handle zum Standard-Ausgabe-Stream
▻ public static final FileDescriptor err Handle zum Standard-Fehlerausgab-Stream
public boolean valid()
public void sync() throws SyncFailedException
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 354 – 01 – TH – 04 ------------------------------------------------------------------------------------
Dateizugriff in Java (4-1)
•••• Die File-Stream-Klassen
◇ Objekte dieser Klassen ermöglichen einen sequentiellen Zugriff zu Dateien :
▻ FileInputStream (byteweises Lesen)
▻ FileOutputStream (byteweises Schreiben)
▻ FileReader (zeichenweises Lesen)
▻ FileWriter (zeichenweises Schreiben)
◇ Überblick über die Konstruktoren : Beispiel : ● Bei der Erzeugung eines File-Stream-Objekts für einen Dateizugriffspfad (Param. vom Typ String bzw. File)
▻ wird die referierte Datei – falls sie vorhanden und die jeweilige Zugriffsart zulässig ist – geöffnet
▻ und ein an sie gebundenes FileDescriptor-Objekt erzeugt. Die Konstruktoren der Datei-Ausgabe-Stream-Klassen versuchen die referierte Datei neu anzulegen, falls sie nicht existiert. Kann eine Datei nicht geöffnet werden (z.B. weil der Zugriffspfad ein Directory referiert), wird eine FileNotFoundException geworfen. ● Bei der Erzeugung eines File-Stream-Objekts für eine bereits geöffnete Datei (Parameter vom Typ FileDescriptor)
▻ wird zu der Datei – falls die jeweilige Zugriffsart zulässig ist – ein weiterer Zugriffskanal geöffnet ● Alle Konstruktoren werfen eine SecurityException, wenn ein SecurityManager-Objekt existiert und dieser feststellt, dass die jeweilige Zugriffsart nicht zulässig ist.
◇ Schliessen eines File-Streams mittels der für alle File-Stream-Klassen existierenden Methode
▻ Die Methode schliesst den File-Stream und damit die referierte Datei und gibt alle sonstigen mit dem Stream assoziierten System-Resourcen frei. Beim Auftritt eines I/O-Fehlers wird eine IOException geworfen.
1.Parameter 2. Parameter existiert für Klasse String path
Dateizugriffspfad FileInputStream FileOutputStream
File fil ------- FileReader
repräsentiert Dateizugriffspfad FileWriter
FileDescriptor fd
referiert geöffnete Datei String path
Dateizugriffspfad boolean app FileOutputStream
wenn true : Anhängen an Datei (append) FileWriter
File fil wenn false : Schreiben am Dateianfang repräsentiert Dateizugriffspfad
public void close() throws IOException
public FileInputStream(File datei) throws FileNotFoundException
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 354 – 02 – TH – 05 ------------------------------------------------------------------------------------
Dateizugriff in Java (4-2)
•••• Die File-Stream-Klassen, Forts.
◇ Ermittlung des assoziierten FileDescriptor-Objekts Dies ist nur für die Klassen FileInputStream und FileOutputStream möglich. Für diese Klassen existiert die Methode
▻ Die Methode gibt das mit dem Stream-Objekt assoziierte FileDescriptor-Objekt zurück. Beim Auftritt eines I/O-Fehlers wird eine IOException geworfen.
◇ Methoden zum Dateizugriff Die File-Stream-Klassen stellen das von ihrer jeweiligen Basisklasse definierte Stream-Zugriffs-Interface zur Verfügung. Die wichtigsten Methoden dieser Interfaces sind : Es existieren noch weitere Methoden, mit denen auch Teile eines Byte- bzw Zeichen-Arrays gelesen bzw Teile eines Strings geschrieben werden können. Alle Methoden für den Dateizugriff werfen eine IOException, wenn ein I/O-Fehler auftritt. � alle Methoden sind mit der throws-Klausel throws IOException definiert.
void write(int b) Schreiben des Bytes b FileOutputStream
void write(byte[] buff) Schreiben des Byte-Buffers buff void write(byte[] buff, Schreiben von len Bytes aus buff int pos, int len) ab Position pos
void write(int c) Schreiben des Zeichens c FileWriter
void write(char[] buff) Schreiben des Zeichen-Buffers buff void write(char[] buff, Schreiben von len Zeichen aus buff int pos, int len) ab Position pos void write(String str) Schreiben des Strings str
void flush() Herausschreiben aller Schreib-Buffer FileOutputStream
(Übergabe an das Betriebssystem) FileWriter
int read() Lesen eines Bytes (= Funktionswert) FileInputStream
Funktionswert == -1 bei Dateiende int read(byte[] buff) Lesen einer Byte-Folge, Ablage im Buffer buff Funktionswert : Anzahl gelesener Bytes bzw –1 bei Dateiende
int read() Lesen eines Zeichens (= Funktionswert) FileReader
Funktionswert == -1 bei Dateiende int read(char[] buff) Lesen einer Zeichen-Folge, Ablage im Buffer buff Funktionswert : Anzahl gelesener Zeichen bzw –1 bei Dateiende
long skip(long n) Überlesen der nächsten n Bytes FileInputStream
bzw der nächsten n Zeichen FileReader
Methode Wirkung existiert für Klasse
public final FileDescriptor getFD() throws IOException
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 354 – 03 – TH – 01 -----------------------------------------------------------------------------------
Dateizugriff in Java (4-3) •••• Demoprogramm zum Dateizugriff (Kopieren einer Datei) Beispiel für Programmaufruf und -ausgabe
// FileCopy.java import java.io.*; public class FileCopy { public static void main(String[] args) { if (args.length <2) System.out.println("Aufruf : \"java FileCopy quelldatei zieldatei\""); else { try { File ifile = new File(args[0]); FileInputStream in = new FileInputStream(ifile); FileOutputStream out = new FileOutputStream(args[1]); long fsize = ifile.length(); System.out.print("Kopiert wird \"" + args[0]+ "\" (Laenge : "); System.out.println(fsize + " Bytes) nach \"" + args[1]+ "\""); byte[] buff = new byte[512]; int len; while ((len=in.read(buff))>=0) { out.write(buff, 0, len); } out.close(); in.close(); System.out.println("Kopieren der Dateien erfolgreich"); } catch(IOException ex) { System.out.println("Exception : " + ex.getMessage()); } } } }
E:\Java\fhm\ee\vorl\fileacc>java FileCopy ListDir.class ListDir.bin Kopiert wird "ListDir.class" (Laenge : 1100 Bytes) nach "ListDir.bin" Kopieren der Dateien erfolgreich
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 355 – 01 – TH – 02 -----------------------------------------------------------------------------------
Dateizugriff in Java (5-1) •••• Schreiben und Lesen von Daten in Binärdarstellung
◇ Dies wird durch die beiden Klassen DataOutputStream und DataInputStream ermöglicht
◇ Diese beiden Klassen implementieren jeweils ein Interface zum Schreiben bzw Lesen der internen Binärdarstellung von Werten der einfachen Datentypen in bzw aus Streams und damit auch in bzw aus Dateien. Zusätzlich ermöglichen sie eine effiziente Umcodierung zwischen 16-Bit-Unicode-Zeichen und Bytefolgen für das Schreiben/Lesen von Strings (modifizierte UTF-8-Codierung)
◇ Objekte dieser Klassen wirken als Filter, die einen zugrundeliegenden Byte-Stream in geeigneter Weise umsetzen. Eine Referenz auf das zu filternde Byte-Stream-Objekt ist ihrem Konstruktor als Parameter zu übergeben :
▻ public DataOutputStream(OutputStream out)
▻ public DataInputStream(InputStream in) Das zu filternde Stream-Objekt kann natürlich auch ein Objekt der Klasse FileOutputStream (abgeleitet von OutputStream) bzw FileInputStream (abgeleitet von InputStream) sein.
◇ Wichtigste Methoden der von DataOutputStream bzw DataInputStream implementierten Interfaces : Alle Methoden für den Stream-Zugriff werfen eine IOException, wenn ein I/O-Fehler auftritt. Die meisten Lese-Methoden werfen beim vorzeitigen Erreichen des Stream-Endes eine EOFException � alle Methoden sind mit der throws-Klausel throws IOException definiert.
◇ Beide Klassen stellen noch weitere Methoden zum Stream-Zugriff zur Verfügung.
◇ Anmerkung zur modifizierten UTF-8-Codierung :
▻ UTF = Universal Transfer Format : effiziente Codierung von Unicode-Zeichen durch 1, 2 und 3 Bytes
▻ Zeichen zwischen '\u0001' und '\u007F' durch ein Byte : 01 ... 7F
Zeichen zwischen '\u0080' und '\u07FF' durch zwei Bytes : C2 80 ... DF BF Zeichen zwischen '\u0800' und '\uFFFF' durch drei Bytes : E0 A0 80 ... EF BF BF der NUL-Character (das Zeichen '\u0000') durch zwei Bytes : C0 80
▻ writeUTF(str) schreibt vor der eigentlichen den String str codierenden Bytefolge deren Länge als short-Wert (2 Bytes) in den Stream.
DataOutputStream DataInputStream Datentyp (Schreiben) (Lesen) void writeBoolean(boolean b) boolean readBoolean() boolean
void writeByte(int b) byte readByte() byte
void writeChar(int c) char readChar() char
void writeShort(int s) short readShort() short
void writeInt(int i) int readInt() int
void writeLong(long l) long readLong() long
void writeFloat(float f) float readFloat() float
void writeDouble(double d) double readDouble() double
void writeBytes(String str) --- String als Byte-Folge void writeChars(String str) --- String als Char-Folge void writeUTF(String str) String readUTF() String (UTF-8-Cod.)
void write(int b) int read() byte
void write(byte[] ba) int read(byte[] ba) byte-Array void write(byte[] ba, int read(byte[] ba, byte-Array (Länge int off, int len) int off, int len len ab Offset off)
DataInputStream FileInputStream
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 355 – 02 – TH – 02 -----------------------------------------------------------------------------------
Dateizugriff in Java (5-2) •••• Demoprogramm zum Schreiben von Daten in Binärdarstelung Programmaufruf und -ausgabe
// DataStreamDemo.java import java.io.*; public class DataStreamDemo { public static String byteToHex(byte b) { String str = Integer.toHexString(b & 0x00FF); if (str.length() == 1) str = '0' + str; return str; } public static void main(String[] args) { if (args.length <1) System.out.println("Aufruf : \"java DataStreamDemo dateipfad\""); else { try { File fil = new File(args[0]); FileOutputStream fout = new FileOutputStream(fil); DataOutputStream dout = new DataOutputStream(fout); dout.writeBoolean(true); dout.writeInt(124); dout.writeDouble(3.14); dout.writeUTF("Hallo Java-Freunde"); dout.writeUTF("\u007F\u0080\u07FF\u0800\uFFFF\u0000"); dout.close(); FileInputStream fin = new FileInputStream(fil); System.out.println("Inhalt der Datei \"" + args[0] + "\" :"); int b; int cnt = 0; while((b=fin.read())!=-1) { cnt++; String hex = byteToHex((byte)b); System.out.print(hex + ' '); if (cnt%25 == 0) System.out.println(); } System.out.println(); fin.close(); } catch(IOException ex) { System.out.println("Exception : " + ex.getMessage()); } } } }
E:\Java\fhm\ee\vorl\fileacc>java DataStreamDemo demo.dat Inhalt der Datei "demo.dat" : 01 00 00 00 7c 40 09 1e b8 51 eb 85 1f 00 12 48 61 6c 6c 6f 20 4a 61 76 61 2d 46 72 65 75 6e 64 65 00 0d 7f c2 80 df bf e0 a0 80 ef bf bf c0 80
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 356 – 01 – TH – 03 ------------------------------------------------------------------------------------
Dateizugriff in Java (6-1)
•••• Zugriff zu Textdateien
◇ Der Zugriff zu Textdateien erfolgt sinnvollerweise über puffernde Zeichen-Stream-Objekte. Diese werden durch die Klassen BufferedWriter (abgeleitet von Writer) und BufferedReader (abge- leitet von Reader) zur Verfügung gestellt.
◇ Die Objekte beider Klassen kapseln jeweils ein anderes Writer- bzw Reader-Objekt. Eine Referenz auf dieses ist dem jeweiligen Konstruktor als Parameter zu übergeben.
▻ public BufferedWriter(Writer out)
▻ public BufferedReader(Reader in) Durch Verwendung eines FileWriter- (indirekt abgeleitet von Writer) bzw FileReader- (indirekt abgeleitet von Reader) Objekts als Konstruktor-Parameter erhält man pufferende Zeichen-Stream-Objekte für den Dateizugriff.
◇ Obige Konstruktoren erzeugen Zeichen-Stream-Objekte, deren Puffer eine Standard-Default-Größe besitzen. Diese Grösse ist für die meisten Anwendungsfälle groß genug. Es existieren aber auch Konstruktoren, denen die Puffergröße als zweiter Parameter zu übergeben ist.
◇ Methoden der Klassen BufferedWriter und BufferedReader
▻ Beide Klassen stellen alle Methoden des jeweiligen Stream-Zugriffs-Interfaces der Klassen FileWriter bzw FileReader sowie die Methode close() zur Verfügung
▻ Darüberhinaus besitzen sie aber einige zusätzliche Memberfunktionen : Auch diese Methoden werfen eine IOException, wenn ein I/O-Fehler auftritt. � sie sind mit der throws-Klausel throws IOException definiert.
▻ Zusätzlich verfügt die Klasse BufferedReader über Memberfunktionen zum Markieren und späteren Wiedereinnehmen einer bestimmten Position im Stream. •••• Weitere Stream-Filter-Klassen
◇ Im Package java.io sowie in einigen anderen Packages (z.B. java.util.zip) sind noch weitere Stream- Klassen enthalten, die als Filter von anderen Stream-Objekten und damit auch von File-Stream-Objekten eingesetzt werden können. Dadurch lassen sich File-Stream-Objekte mit weiteren speziellen Eigenschaften versehen.
◇ Beispiele : FilterReader abstrakte Basisklasse für – eigene – Reader-Filter-Klassen LineNumberReader Klasse zum zeilenorientierten Lesen aus Zeichen-Streams PrintWriter Klasse zur Ausgabe der externen Darstellung von Datenwerten in Zeichen-Streams PrintStream Klasse zur Ausgabe der externen Darstellung von Datenwerten in Byte-Streams PushbackInputStream Klasse, die die Rückgabe gelesener Bytes in einen Eingabe-Byte-Stream ermöglicht CheckedOutputStream Klasse, die an einen Ausgabe-Stream eine Prüfsumme anhängt.
BufferedReader FileReader
void newLine() Schreiben eines Zeilenendes BufferedWriter
String readLine() Lesen einer Zeile, Rückgabe als String BufferedReader Rückgabe von null, wenn am Dateiende
Methode Wirkung existiert für Klasse
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 356 – 02 – TH – 01 -----------------------------------------------------------------------------------
Dateizugriff in Java (6-2) •••• Demoprogramm zum Zugriff zu Textdateien : Ausgabe einer Textdatei am Bildschirm
// TextFileList.java import java.io.*; public class TextFileList { public static void main(String[] args) { if (args.length <1) System.out.println("Aufruf : \"java TextFileList dateipfad\""); else { try { File fil = new File(args[0]); if (!fil.exists()) System.out.println("Datei \"" + args[0] + "\" existiert nicht"); else { BufferedReader tf = new BufferedReader(new FileReader(args[0])); String line; while ((line=tf.readLine()) != null) System.out.println(line); tf.close(); } } catch(IOException ex) { System.out.println("Exception : " + ex.getMessage()); } } } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 356 – 03 – TH – 02 ------------------------------------------------------------------------------------
Dateizugriff in Java (6-3) •••• Formatiertes Schreiben in Textdateien (ab dem JDK 5.0)
◇ Mittels eines Objekts der Klasse Formatter
▻ Die Klasse Formatter (Package java.util) dient zum Erzeugen formatierter Textdarstellungen. Formatter-Objekte können auch an Dateien gebunden werden. Damit lassen sie sich zur formatierten Ausgabe in Textdateien einsetzen.
▻ Die jeweilige Datei ist durch Übergabe eines die Datei referierenden Objekts an den Konstruktor festzulegen. Ein derartiges Objekt kann u.a. sein :
▹ Objekt der Klasse FileOutputStream (z.B. Konstruktor Formatter(OutputStream os))
▸ Objekt der Klasse FileWriter (z.B. Konstruktor Formatter(Appendable a))
▸ Objekt der Klasse File (z.B. Konstruktor Formatter(File file))
▻ Mit der Formatter-Methode Formatter format(String format, Object... args) kann formatierter Text in die Datei geschrieben werden. Die Parameter entsprechen den Parametern der PrintStream-(und PrintWriter-) Methode printf() : - format ist der anzuwendende Format-String Syntax und Semantik des Format-Strings ist die gleiche wie beim Format-String der Methode printf() - args sind die zu schreibenden (und in Textdarstellung umzuwandelnden) Werte Rückgabewert : aktuelles Formatter-Objekt
▻ Beispiel :
Formatter FileOutputStream
public void formOutDouble1(String dpfad, int anz) throws IOException { File datei = new File(dpfad); //Formatter form = new Formatter(datei); //Formatter form = new Formatter(new FileOutputStream(datei)); Formatter form = new Formatter(new FileWriter(datei)); Random rand = new Random(); for (int j=1; j<=anz; ++j) { form.format("%.5f ", rand.nextDouble()); if (j%8==0) form.format("%n"); } form.close(); }
Formatter FileWriter
Formatter File
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 356 – 04 – TH – 01 -----------------------------------------------------------------------------------
Dateizugriff in Java (6-4) •••• Formatiertes Schreiben in Textdateien, Forts. (ab dem JDK 5.0)
◇ Mittels der PrintStream- (und PrintWriter-) Methode printf()
▻ Die – u.a. für die Standardausgabe eingesetzte –Klasse PrintStream ermöglicht die Ausgabe von Strings und der externen Textdarstellung von Datenwerten in beliebige Byte-Streams, somit auch in Dateien.
▻ Analog dient die Klasse PrintWriter zur Ausgabe derartiger Informationen in Zeichen-Streams und damit ebenfalls in entsprechende Dateien.
▻ Für beide Klassen ist die Datei bei der Objekt-Erzeugung durch Übergabe eines sie referierenden Objekts an den jeweiligen Konstruktor festzulegen. U.a. existieren die folgenden Konstruktoren :
▹ PrintStream(OutputStream os) (OutputStream ist u.a. Basisklasse von FileOutputStream)
▹ PrintStream(File file)
▹ PrintWriter(Writer out) (Writer ist u.a. Basisklasse von FileWriter)
▹ PrintWriter(File file)
▻ Beide Klassen stellen ab dem JDK 5.0 zur formatierten Ausgabe die Memberfunktion printf() zur Verfügung
▹ Klasse PrintStream : PrintStream printf(String format, Object... args)
▹ Klasse PrintWriter : PrintWriter printf(String format, Object... args) Beschreibung der Parameter sowie der Wirkungsweise der Funktion siehe "Standardausgabe - Formatierte Ausgabe"
▻ Beispiel :
PrintStream FileOutputStream
PrintStream File
PrintWriter File
PrintWriter FileWriter
public void formOutDouble2(String dpfad, int anz) throws IOException { File datei = new File(dpfad); PrintStream prnt = new PrintStream(datei); //PrintStream prnt = new PrintStream(new FileOutputStream(datei)); //PrintWriter prnt = new PrintWriter(datei); //PrintWriter prnt = new PrintWriter(new FileWriter(datei)); Random rand = new Random(); for (int j=1; j<=anz; ++j) { prnt.printf("%.5f ", rand.nextDouble()); if (j%8==0) prnt.printf("%n"); } prnt.close(); }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 356 – 05 – TH – 02 -----------------------------------------------------------------------------------
Dateizugriff in Java (6-5) •••• Formatiertes Lesen aus Textdateien (ab dem JDK 5.0)
◇ Hierfür lässt sich die Klasse Scanner einsetzen
◇ Scanner-Objekte dienen zum Zergliedern und Interpretieren von Zeichenfolgen. Diese Zeichenfolgen können auch von Zeichen- und Byte-Streams und damit auch von Dateien geliefert werden.
◇ Die jeweilige Zeichenquelle ist einem Scanner-Objekt im Konstruktor zu übergeben, u.a. als Objekt der
▻ Klasse FileInputStream (Konstruktor Scanner(InputStream source))
▻ Klasse FileReader (Konstruktor Scanner(Readable source))
▻ Klasse File (Konstruktor Scanner(File source))
◇ Beschreibung der Funktionalität der Klasse Scanner siehe "Standard- Ein- und Ausgabe in Java".
◇ Beispiel : Funktion zum Lesen aus Textdateien, deren Inhalt prinzipiell wie folgt aufgebaut ist. Die gelesenen Werte werden im gleichen Format in die Standard-Ausgabe ausgegeben (Memberfunktion der Klasse FormTextFileDemo)
2 : 0,44507 0,06490 3 : 0,25472 0,13943 0,40664 1 : 0,96712 6 : 0,78277 0,24195 0,54913 0,99872 0,71365 0,14333 3 : 0,54464 0,03770 0,15014
public void formInput() throws IOException { // String dpfad ist Datenkomponente der Klasse FormTextFileDemo File datei = new File(dpfad); Scanner scan = new Scanner(datei); //Scanner scan = new Scanner(new FileInputStream(datei)); //Scanner scan = new Scanner(new FileReader(datei)); try { while (scan.hasNext()) { int anz = scan.nextInt(); System.out.printf("%d : ", anz); scan.next(); // Ueberlesen des ':' double d; for (int i = 1; i <= anz; ++i) { d = scan.nextDouble(); System.out.printf("%.5f ", d); } System.out.printf("%n"); } } catch (InputMismatchException ex) { System.err.println("Type Mismatch beim Lesen."); } scan.close(); }
Scanner File *) *) bzw FileInputStream oder FileReader
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 357 – 01 – TH – 03 -----------------------------------------------------------------------------------
Dateizugriff in Java (7-1)
•••• Wahlfreier Zugriff zu Dateien
◇ Für den wahlfreien Zugriff zu Dateien steht die Klasse RandomAccessFile zur Verfügung. Diese Klasse ist von keiner der File-Stream-Klassen sondern direkt von Object abgeleitet.
◇ Durch Objekte dieser Klasse können Dateien für einen wahlfreien Zugriff nur zum Lesen oder zum Lesen und Schreiben geöffnet werden. Der wahlfreie Zugriff wird durch die Möglichkeit zur expliziten Veränderung der aktuellen Bearbeitungsposition (File-Pointer) realisiert.
◇ Konstruktoren der Klasse RandomAccessFile
▻ public RandomAccessFile(String path, String mode) throws FileNotFoundException
▻ public RandomAccessFile(File fil, String mode) throws FileNotFoundException Der erste Parameter referiert die zu bearbeitende Datei (über den Zugriffspfad bzw ein File-Objekt, das diesen repräsentiert) Der zweite Parameter legt die Zugriffsart fest :
▻ "r" nur Lesen,
▻ "rw" Lesen und Schreiben. ("rws" und "rwd" sind auch zulässig) Die Konstruktoren versuchen die referierte Datei für die angegebene Zugriffsart zu öffnen. Falls die referierte Datei nicht existiert wird bei der Zugriffsart "rw" versucht, sie zu erzeugen. Die Konstruktoren können die folgenden Exceptions werfen :
▻ FileNotFoundException, falls die referierte Datei nicht existiert (Zugriffsart "r") oder ein Directory ist oder nicht erzeugt werden kann oder aus einem anderen Grund nicht geöffnet werden kann.
▻ SecurityException, falls für die vorgesehene Zugriffsart keine Berechtigung besteht
▻ IllegalArgumentException, falls ein nicht zulässiger String für die Zugriffsart angegeben wird.
◇ Methoden der Klasse RandomAccessFile zum Dateizugriff : Die Klasse stellt für den Dateizugriff die gleichnamigen Methoden mit gleicher Signatur wie die Klassen DataInputStream und DataOutputStream zur Verfügung. Wie bei diesen Klassen werfen die Zugriffsmethoden eine IOException beim Auftritt eines I/O-Fehlers. Die meisten Lesemethoden werfen darüber hinaus eine EOFException beim vorzeitigen Erreichen des Dateiendes
◇ Weitere Methoden der Klasse RandomAccessFile (Auswahl) Alle o.a. Methoden werfen eine IOException wenn ein I/O-Fehler auftritt. � sie sind mit der throws-Klausel throws IOException definiert.
Methode Wirkung
void seek(long pos) Setzen der Bearbeitungsposition auf pos Bytes nach dem Dateianfang long getFilePointer() Rückgabe der aktuellen Bearbeitungsposition (in Bytes bezogen auf den Dateianfang) int skipBytes(int cnt) Versuch, die Bearbeitungsposition um cnt Bytes weiterzusetzen Rückgabe der Anzahl Bytes, um die tatsächlich weitergesetzt wurde String readLine() Lesen der nächsten Zeile (=Rückgabewert), Bytes werden zu Zeichen ergänzt (höherwertiges Byte == NUL-Byte) long length() Rückgabe der Dateilänge FileDescriptor getFD() Rückgabe des assoziierten FileDescriptor-Objekts void close() Schliessen der Datei und Freigabe aller belegten Resourcen
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 357 – 02 – TH – 02 -----------------------------------------------------------------------------------
Dateizugriff in Java (7-2) •••• Demoprogramm zum wahlfreien Dateizugriff Beispiele für Programmaufruf und -ausgabe
// RandAccDemo.java // Zufallsgesteuerte Auswahl eines Spruches aus einer Textdatei mit Spruechen. // Die einzelnen Sprueche sind jeweils durch eine Zeile, // die nur das Zeichen '*' enthaelt, getrennt. import java.io.*; public class RandAccDemo { public static void main(String[] args) { try { RandomAccessFile raf = new RandomAccessFile("sprueche.txt", "r"); long pos = (long)(raf.length()*Math.random()); raf.seek(pos); while((pos!=0) && ((char)raf.read()!='*')) raf.seek(--pos); int ch; if (pos==0) System.out.println(); while (((ch=raf.read())!=-1) && ((char)ch!='*')) { System.out.print((char)ch); } System.out.println(); raf.close(); } catch (IOException ex) { System.out.println(ex); } } }
E:\Java\fhm\ee\vorl\fileacc>java RandAccDemo Gut gehaengt ist besser als schlecht verheiratet.
E:\Java\fhm\ee\vorl\fileacc>java RandAccDemo Es ist nicht genug, dass man redet, man muss auch richtig reden.
E:\Java\fhm\ee\vorl\fileacc>java RandAccDemo Ein Tor nur schliesst aus aeusserem Gehaben getrost auf eines Menschen innere Gaben.
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 358 – 00 – TH – 01 ------------------------------------------------------------------------------------
Dateizugriff in Java – Zusammenfassender Überblick
Datei- bzw Verwendungsart Klasse Konstruktorparameter wichtige (Auswahl) Zugriffsmethoden
sequentieller byteweiser FileInputStream File-Objekt oder read()
Zugriff FileOutputStream Dateizugriffspfad write()
sequentieller zeichenweiser FileReader File-Objekt oder read()
Zugriff FileWriter Dateizugriffspfad write()
Lesen/Schreiben von DataInputStream FileInputStream-Obj. readInt() usw Daten in Binärdarstellung DataOutputStream FileOutputStream-Obj. writeInt() usw
Lesen/Schreiben von BufferedReader FileReader-Objekt read()
Textdateien readLine() BufferedWriter FileWriter-Objekt write() newLine()
Formatiertes Schreiben Formatter File-Objekt oder format()
in Textdateien FileWriter-Objekt oder FileOutputStream-Obj PrintStream File-Objekt oder printf()
FileOutputStream-Obj PrintWriter File-Objekt oder printf()
FileWriter-Objekt
Formatiertes Lesen Scanner File-Objekt oder nextLine()
aus Textdateien FileReader-Objekt oder hasNextLine()
FileInputStream-Obj. next() hasNext()
nextInt() usw
wahlfreier Zugriff RandomAccessFile File-Objekt oder seek()
Dateizugriffspfad getFilePointer()
+ Zugriffsmodus (String) skipBytes() read() readLine()
readInt() usw write()
writeInt() usw length()
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 400 – 00 – TH – 03 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 4
4. Nähere Betrachtung von Klassen und Interfaces 4.1. Definition von Klassen 4.2. Datenkomponenten 4.3. Memberfunktionen 4.4. Objekterzeugung 4.5. Konstruktoren und Initialisierungsblöcke 4.6. Vererbung 4.7. Interfaces 4.8. Eingebettete Klassen und Interfaces 4.9. Generische Klassen, Interfaces und Funktionen
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 411 – 00 – TH – 03 -----------------------------------------------------------------------------------
Definition von Klassen in Java (1)
•••• Vorbemerkungen
◇ Klassen sind die grundlegenden Programmiereinheiten in Java. Jedes Java-Programm besteht aus einer oder mehreren Klassen. Es existiert kein Code ausserhalb einer Klasse.
◇ I.a. ist jede Klasse in einer eigenen Quelldatei definiert (Ausnahme : eingebettete Klassen). Diese Klassen-Quelldateien bilden die Übersetzungseinheiten (Übersetzungs-Module). Pro Klasse (auch für jede eingebettete Klasse) wird vom Compiler eine eigene Byte-Code-Datei erzeugt.
◇ Klassen definieren den Aufbau und die Funktionalität (das Verhalten) von Objekten. Objekte sind Instanzen von Klassen. Sie bestehen aus Datenkomponenten (Felder, fields), die ihren Zustand beschreiben und besitzen Funktionen (Memberfunktionen, Methoden, methods), die mit diesen Datenkomponenten arbeiten und ihr Verhalten festlegen. Die Datenkomponenten und die (Member-)Funktionen werden in einer Klassendefinition festgelegt und als Klassenkomponenten bezeichnet.
◇ Neben den instanzspezifischen Datenkomponenten (Instanz-Variable) und Memberfunktionen (Instanz-Methoden) kann eine Klasse auch klassenspezifische Datenkomponenten (Klassen-Variable) und Memberfunktionen (Klassen- Methoden) besitzen. Derartige statische Klassenkomponenten beschreiben den Zustand und das Verhalten der Klasse.
◇ Instanz-Methoden wird als impliziter Parameter die this-Referenz übergeben. Diese referiert das aktuelle Objekt, für das die Methode aufgerufen wird. Klassen-Methoden besitzen diesen impliziten Parameter nicht. •••• Klassenkomponenten
◇ Klassenkomponenten (class members) können sein :
▻ Datenkomponenten (Membervariable, Felder, fields)
▻ Funktionskomponenten (Memberfunktionen, Methoden, methods)
▻ Eingebettete Klassen und Interfaces (nested classes and interfaces)
◇ Zusätzlich kann eine Klassendefinition enthalten :
▻ Konstruktoren (Sie werden in Java nicht zu den Memberfunktionen gerechnet)
▻ Initialisierungsblöcke (Code zur Initialisierung von Datenkomponenten) •••• Syntax der Klassendefinition :
◇ Einfachste Klassendefinition : class Simple
{
;
}
class Klassen-Name
Interface-
Implementierung
Klassen- Modifizierer
;
{ Komponentendefinition
Konstruktordefinition
}
Initialisierungsblock
Klassen-
Ableitung
Typ-Param-
Deklaration
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 412 – 00 – TH – 04 ------------------------------------------------------------------------------------
Definition von Klassen in Java (2)
•••• Anmerkung zur Typ-Param-Deklaration Deklaration von formalen Typ-Parametern (Typ-Variable). Falls vorhanden, wird dadurch eine generische Klasse definiert. •••• Klassen-Modifizierer
◇ Sie legen bestimmte Eigenschaften der Klasse fest
◇ Folgende Modifizierer sind möglich :
▻ public Die Klasse ist öffentlich zugänglich – sie kann überall verwendet werden. Ohne diesen Modifizierer ist sie nur innerhalb des Packages, in dem sie enthalten ist, verwendbar. ▻ abstract Die Klasse ist unvollständig definiert oder sie wird als unvollständig definiert betrachtet (abstrakte Klasse). Damit ist sie nicht instanzierbar. I.a. besitzt sie eine oder mehrere abstrakte Methoden. Eine abstrakte Methode besitzt keine vollständige Definition. Häufig ist sie lediglich deklariert. Ihre – vollständige – Definition bleibt einer abgeleiteten Klasse überlassen. ▻ final Von der Klasse können keine weiteren Klassen abgeleitet werden. Damit können ihre Methoden niemals überschrieben werden.
▻ strictfp Alle innerhalb der Klasse (und allen eingebetteten Klassen) auftretenden float- oder double-Ausdrücke sind FP-strict. D.h. sie werden so ausgewertet, dass auch alle Zwischenergebnisse mit der in IEEE 754 festgeleg- ten einfachen (float) bzw doppelten (double) Genauigkeit für Gleitpunktwerte ermittelt werden. Dadurch wird sichergestellt, dass ein arithmetischer Ausdruck unabhängig von der jeweiligen JVM immer den exakt gleichen Wert ergibt. Ohne diesen Modifizierer (der auch auf der Methoden-Ebene eingesetzt werden kann), darf die JVM Zwischen- ergebnisse mit erweiterter Genauigkeit (größerer Exponentenbereich) bilden. Dies kann dazu führen, dass die Auswertung desselben arithmetischen Ausdrucks auf unterschiedlichen JVMs leicht unterschiedliche Ergebnisse liefert.
◇ Eine Klassendefinition kann mehrere Klassen-Modifizierer besitzen. Allerdings ist die gleichzeitige Verwendung von abstract und final nicht möglich.
◇ Anmerkung : Der Modifizierer abstract sollte nur für Klassen eingesetzt werden, von denen auch tatsächlich Klassen zur Vervollständigung der Implementierung abgeleitet werden sollen. Er ist nicht dafür vorgesehen, die Instanzierung von Klassen aus einem anderen Grund als der unvollständigen Definition zu verhindern. Ein solcher anderer Grund kann beispielsweise sein, dass die Klasse nur statische Klassen- komponenten enthält und damit ihre Instanzierung nicht sehr sinnvoll ist. In einem derartigen Fall besteht die saubere Lösung zur Verhinderung der Instanziierung in der Definition eines privaten Default-Konstruktors und keiner weiteren Konstruktoren. Durch Verwendung des Modifizierers final kann darüber hinaus verhindert werden, dass von der Klasse andere Klassen abgeleitete werden. Beispiel : Bibliotheks-Klasse Math Diese ist eine reine Utility-Klasse, die nur statische Datenkomponenten und statische Methoden zur Verfügung stellt. public final class Math { private Math() { } // privater Default-Konstruktor // statische Klassenkomponenten }
•••• Kontrakt einer Klasse (contract of the class) Die Gesamtheit der von außen zugänglichen Methoden und Datenkomponenten einer Klasse, zusammen mit der Beschreibung ihres Verhaltens, wird häufig als Kontrakt der Klasse bezeichnet.
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 413 – 00 – TH – 02 -----------------------------------------------------------------------------------
Definition von Klassen in Java (3) •••• Unterschiede zur Klassendefinition in C++
◇ Eine Klassendefinition in Java kann Klassen-Modifizierer enthalten.
◇ Eine Klassendefinition in Java wird nicht mit einem Semicolon (';') abgeschlossen.
◇ Andere Syntax zur Kennzeichnung einer Vererbung (s. später).
◇ Memberfunktionen müssen in Java innerhalb der Klassendefinition definiert werden. Sie werden dadurch nicht zu inline-Funktionen (inline-Funktionen gibt es nicht in Java !)
◇ Für Datenkomponenten können in Java Initialisierungswerte festgelegt werden. Zusätzlich sind Initialisierungsblöcke möglich (s. später).
◇ In Java muß ein eventueller Zugriffs-Spezifizierer für jede Klassenkomponente gesondert angegeben werden. (Ausnahme : Zusammenfassung mehrerer Datenkomponenten des gleichen Typs in einer Vereinbarung) •••• Vergleich einer Klassendefinition in C++ und Java
// Example.java public class Example { private String name; private int x; public Example(int wx) { x = wx; name = null; } public void setName(String wname) { name = wname; } public void setX (int wx) { x = wx; } public String getName() { return name; } public int getX() { return x; } }
// C++-Header-Datei Example.h // Definition der Klasse Example class Example { public : Example(int wx); ~Example(); void setName(char* wname); void setX(int wx); const char* getName(); int getX(); private : char* name; int x; };
// C++-Quell-Datei Example.cpp // Implementierung der Klasse Example #include "Example.h" #include <cstdlib> // fuer NULL Example::Example(int wx) { x = wx; name = NULL; } Example::~Example() { /* ... */ } void Example::setName(char* wname) { /* ... */ } void Example::setX(int wx) { x = wx; } const char* Example::getName() { return name; } int Example::getX() { return x; }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 421 – 00 – TH – 04 ------------------------------------------------------------------------------------
Datenkomponenten in Java-Klassen (1) •••• Definition von Datenkomponenten
◇ Datenkomponenten von Klassen (Membervariable) werden in Java auch als Felder (fields) bezeichnet.
◇ Die Definition von Datenkomponenten des gleichen Typs kann in einer einzigen Vereinbarung zusammengefasst werden.
◇ Für die – gegebenenfalls in einer Vereinbarung zusammengefassten – Datenkomponenten, die nicht die Zugriffsbe- rechtigung "package" besitzen sollen, ist gesondert eine andere Zugriffsberechtigung anzugeben. Wie in C++ stehen hierfür die Zugriffs-Spezifizierer (in Java auch als Zugriffs-Modifizierer bezeichnet) public, protected und private zur Verfügung.
◇ Zusätzlich können in jeder Datenkomponenten-Vereinbarung weitere Feld-Modifizierer (field modifier) angegeben werden.
◇ Syntax : •••• Initialisierung von Datenkomponenten
◇ Zu jeder Datenkomponente kann bei ihrer Definition ein Initialisierungswert festgelegt werden.
◇ Ohne eine derartige Festlegung wird eine Datenkomponente mit einem vorgegebenen Default-Wert initialisiert (s. "Datentypen")
◇ Der einen Initialisierungswert festlegende Initialisierer (variable initializer) darf sein
▻ ein beliebiger Ausdruck, der einen Wert liefert, der zuweisungskompatibel zum Typ der Datenkomponente ist und keine geprüften Exceptions erzeugen kann. Weiterhin darf ein Ausdruck zur Initialisierung einer Klassen-Variablen keine Instanz-Variable enthalten
▻ ein Array-Initialisierer (array initializer), wenn die Datenkomponente ein Array ist (s. "Arrays").
◇ Beispiele für gültige Initialisierer :
◇ Zur Realisierung komplexerer Initialisierungsaufgaben können Initialisierungsblöcke definiert werden (s. später).
◇ Ein Initialisierer für eine Instanz-Variable wird bei jeder Instanzierung (Objekterzeugung) der Klasse ausgewertet. Ein Initialisierer für eine Klassen-Variable wird nur einmal beim Laden der Klasse in die JVM ausgewertet
◇ Eine Initialisierung von Instanz-Variablen kann auch in einem Konstruktor erfolgen. Gegebenenfalls werden "vorherige" Initialisierungen dadurch überschrieben.
public class InitDemo { double zero = 0.0; // Konstante double sum = 4.5 + 3.7; // konstanter Ausdruck double zeroCpy = zero; // andere Datenkomponente double wurz2 = Math.sqrt(2); // Methodenaufruf double some = sum + 2*Math.sqrt(wurz2); // gemischter Ausdruck int[] koeff = { 2, 4, 1, 3, 6, 7 }; // Array-Initialisierer double[] tfeld = { Math.sin(1), Math.cos(1), Math.tan(1) }; // Array-Init. }
Feld-Modifizierer
= Typangabe Komponentenname
,
Initialisierer ;
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 422 – 00 – TH – 05 ------------------------------------------------------------------------------------
Datenkomponenten in Java-Klassen (2)
•••• Feld-Modifizierer
◇ Sie legen bestimmte Eigenschaften einer Datenkomponente fest.
◇ Folgende Modifizierer sind möglich :
▻ die Zugriffs-Spezifizierer (Zugriffs-Modifizierer) public, protected und private.
▻ static Die Datenkomponente ist eine Klassen-Variable (statische Datenkomponente). Klassen-Variable müssen von ausserhalb (vorausgesetzt es besteht eine entsprechende Zugriffsberechtigung) mit ihrem vollqualifizierten Namen (Ergänzung um Klassenname und . –Operator) angesprochen werden. Sie können allerdings auch als Komponente eines Objekts ihrer Klasse angesprochen werden. Dies sollte jedoch aus semantischen Gründen zur Vermeidung von Missverständnissen unterbleiben.
▻ final Die Datenkomponente kann nach ihrer Initialisierung nicht mehr verändert werden. Sowohl Instanz- als auch Klassenvariable können diese Eigenschaft besitzen. Typischerweise wird eine als final vereinbarte Datenkomponente einen Initialisierer besitzen. Fehlt ein Initialisierer (blank final), so muß eine final-Klassen-Variable durch einen Initialisierungsblock, eine final-Instanz-Variable durch einen Initialisierungsblock oder durch einen Konstruktor initialisiert werden. Das Fehlen einer Initialisierung sowie der Versuch einer späteren Wertzuweisung führt zu einem Compiler-Fehler
▻ transient Die Datenkomponente gehört nicht zum persistenten Zustand eines Objekts. Beim persistenten Abspeichern des Objekts wird eine transient-Datenkomponente nicht mit abgespeichert.
▻ volatile Zu der Datenkomponente kann durch mehrere unsynchronisierte Threads zugegriffen werden. Der Compiler muß durch Vermeidung von Zugriffs-Optimierungen sicherstellen, dass die Datenkomponente sich immer in einem konsistenten Zustand befindet. Z.B. muß ein Thread jeden Zugriff zu einer von ihm gehaltenen lokalen Kopie einer derartigen Variablen immer mit der Original-Variablen abgleichen.
◇ Mehrere Feld-Modifizierer dürfen – soweit sinnvoll – miteinander kombiniert werden. Allerdings ist nur jeweils ein Zugriffs-Spezifizierer zulässig. Ausserdem kann eine Datenkomponente nicht gleichzeitig volatile und final sein. •••• Konstante in Java
◇ Konstante werden in Java i.a. als final-Klassen-Variable (Datenkomponenten mit den Modifizierern static und final) definiert. Es ist üblich – aber nicht verpflichtend – , Konstanten-Namen mit Großbuchstaben zu bilden.
◇ Beispiele aus der Java-Standard-Bibliothek
◇ Es lassen sich mit dem Schlüsselwort final auch lokale Konstante in Funktionen definieren : final int ANZ = 10; Sofern diese nicht bei ihrer Definition initialisiert werden, kann ihnen später einmal ein Wert zugewiesen werden. Jeder Versuch einer weiteren Wertzuweisung führt zu einem Compilerfehler
public final class Integer { public static final int MAX_VALUE; public static final int MIN_VALUE; ..public static final Class<Integer> TYPE; // ... } public final class System { public static final InputStream in; ..// ... }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 431 – 00 – TH – 04 ------------------------------------------------------------------------------------
Memberfunktionen in Java (1) •••• Definition von Memberfunktionen
◇ Jede Memberfunktion (Methode) muß – sofern es sich nicht um eine abstrakte Methode handelt – innerhalb der Klassendefinition vollständig definiert (implementiert) werden.
◇ Für jede Memberfunktion, die nicht die Zugriffsberechtigung "package" besitzen soll, ist gesondert eine andere Zugriffsberechtigung anzugeben. Wie in C++ stehen hierfür die Zugriffs-Spezifizierer (in Java auch als Zugriffs-Modifizierer bezeichnet) public, protected und private zur Verfügung.
◇ Können innerhalb einer Methode geprüfte Exceptions – direkt oder indirekt – geworfen werden und werden diese nicht gefangen, so müssen sie im Funktionskopf in einer throws-Klausel deklariert werden.
◇ Syntax :
•••• Anmerkung zur Typ-Param-Deklaration Deklaration von formalen Typ-Parametern (Typ-Variable). Falls vorhanden, wird eine generische Methode definiert. •••• Anmerkungen zur Formal-Parameterliste :
◇ Auflistung der formalen Methoden-Parameter. Syntax weitgehend analog zu C/C++ : Angabe von Typ und Name für jeden Parameter, Trennung der Parameter durch Kommata
◇ Wenn eine Methode keine Parameter besitzt, ist die Formal-Parameterliste leer (keine Angabe von void)
◇ Default-Parameterwerte gibt es in Java nicht.
◇ Parameter eines einfachen Datentyps sind Wertparameter, Parameter eines Klassen-Typs sind Referenzparameter.
◇ Parameter können als final deklariert werden � sie dürfen dann innerhalb der Funktion nicht verändert werden •••• Variable Parameterliste (Varargs)
◇ Seit dem JDK 5.0 ist es möglich, Methoden mit einer variablen Parameterliste (Varargs)zu definieren.
▻ In der Formal-Parameterliste muss hierfür die Typangabe des letzten Parameters von drei Punkten gefolgt werden.
▻ Eine derartige Methode kann mit einer beliebigen Anzahl aktueller Parameter aufgerufen werden. Die aktuellen Parameter müssen zum Typ des letzten formalen Parameters kompatibel sein.
▻ Wenn in einem derartigen Fall aktuelle Parameter beliebigen Typs übergebbar sein sollen, muss als Typangabe Object verwendet werden : Object...
▻ Beispiel : Methode printf() der Klasse PrintStream (bzw PrintWriter) public PrintStream printf(String format, Object... args)
▻ Statt mit einer variablen Anzahl von Parametern lässt sich eine derartige Methode auch mit einem Array, in dem die Parameter zusammengefasst sind, aufrufen
◇ Innerhalb der Methode werden die variablen aktuellen Parameter in einem Array des deklarierten Parametertyps zur Verfügung gestellt. Beispielsweise kann die Anzahl der aktuellen Parameter mittels der öffentlichen Array-Datenkomponente length ermittelt werden.
Methoden-Kopf
Methoden-Rumpf
Methoden- Modifizierer
( Typangabe Methoden-Name Formal-Parameterliste )
Anweisung { }
Typ-Param-
Deklaration throws-Klausel
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 432 – 00 – TH – 05 ------------------------------------------------------------------------------------
Memberfunktionen in Java (2) •••• Demoprogramm zur variablen Parameterliste
•••• Signatur einer Memberfunktion
◇ Der Methoden-Name und die Formal-Parameterliste (Anzahl und Typ der Parameter) bilden die Signatur einer Memberfunktion.
◇ In einer Klasse dürfen nicht zwei Methoden mit der gleichen Signatur definiert werden, auch wenn der Rückgabetyp und / oder die throws-Klausel unterschiedlich ist (� Compiler-Fehler).
◇ Zulässig sind dagegen überladene Methoden : Zwei oder mehr Methoden gleichen Namens, aber unterschiedlicher Parameterliste (� unterschiedliche Signatur). Beispiel :
public class Point { private double x = 0.0; private double y = 0.0; public Point move(double dx, double dy) { x += dx; y += dy; return this; } /* public void move(double px, double py) // unzulaessig { x = px; y = py;} */ public void move(Point p) // zulaessig : überlädt Point move(double, double) { x = p.x; y = p.y;} // ... }
// VarargsDemo.java // Demoprogramm zur variablen Parameter-Liste import java.util.*; public class VarargsDemo { int varargsfunc(Object... pars) { System.out.printf("Aufruf mit %d Parametern\n", pars.length); return pars.length; } public static void main(String[] args) { VarargsDemo vad = new VarargsDemo(); vad.varargsfunc(3, 4, 6.5, "Hallo"); vad.varargsfunc(); vad.varargsfunc("Datum : ", new Date()); Number[] na = new Number[] { 3, 5.6, 7}; vad.varargsfunc(na); } }
Aufruf mit 4 Parametern Aufruf mit 0 Parametern Aufruf mit 2 Parametern Aufruf mit 3 Parametern
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 433 – 00 – TH – 03 -----------------------------------------------------------------------------------
Memberfunktionen in Java (3) •••• Methoden-Modifizierer
◇ Sie legen bestimmte Eigenschaften einer Memberfunktion fest.
◇ Folgende Modifizierer sind möglich :
▻ die Zugriffs-Spezifizierer (Zugriffs-Modifizierer) public, protected und private.
▻ abstract Es handelt sich um eine abstrakte Methode. Für eine derartige Methode wird nur die Signatur (Name und Parameter), der Rückgabetyp und gegebenenfalls die throws-Klausel nicht jedoch die Implementierung festgelegt. (Methode wird nur deklariert) Der Methoden-Rumpf wird durch ein ; ersetzt. Abstrakte Methoden sind nur in abstrakten Klassen zulässig. Jede von der abstrakten Klasse abgeleitete Klasse, die selbst nicht wieder abstrakt ist, muß eine Definition der Methode bereitstellen. ▻ static Die Methode ist eine Klassen-Methode (statische Memberfunktion). Da eine derartige Methode nicht für ein konkretes Objekt aufgerufen werden kann und ihr keine implizite this- Referenz übergeben wird, kann sie direkt nur zu anderen statischen Klassenkomponenten zugreifen. Ein Zugriff zu nicht-statischen Klassenkomponenten der eigenen Klasse ist nur über ein konkretes Objekt möglich, das entweder als Parameter übergeben oder innerhalb der Methode erzeugt werden muß. ▻ final Die Methode kann in einer abgeleiteten Klasse weder überschrieben noch überdeckt werden. Allerdings ist es zulässig, die Methode in einer abgeleiteten Klasse zu überladen, d.h. eine Methode gleichen Namens aber mit anderer Parameterliste zu definieren. Eine private-Methode sowie alle Methoden einer final deklarierten Klasse sind implizit final. Eine explizite Angabe des Modifizierers final für derartige Methoden ist nicht notwendig, aber zulässig. Eine final-Methode kann vom Maschinencode-Generator der JVM als Makro ("inline") expandiert werden.
▻ synchronized Die Methode implementiert einen Synchronisations-Mechanismus für den Aufruf durch konkurierende Threads.
▻ native Dieser Modifizierer erlaubt das Einbinden von Methoden, die in nativen Machinencode vorliegen. Üblicherweise werden derartige Methoden in einer anderen Programmiersprache (z.B. C, C++, FORTRAN, Assem- bler) formuliert und dann in Machinencode übersetzt. Eine native-Methode wird in der Klassendefinition nur deklariert, d.h. der Methoden-Rumpf wird durch ein ; ersetzt. Die den Methoden-Code enthaltene Datei muss zur Laufzeit (üblicherweise bei der Klassen-Initialisierung) in die JVM geladen werden. Hierfür stehen in den Klassen Runtime und System die statischen Methoden load(...) und loadLibrary(...) zur Verfügung. Das Java-SDK definiert ein Interface zum Formulieren und Einbinden von native-Methoden (� JNI, Java Native Interface).
▻ strictfp Eine derartige Methode arbeitet FP-strict. D.h. alle innerhalb der Methode auftretenden float- oder double- Ausdrücke werden so ausgewertet, dass auch alle Zwischenergebnisse mit der in IEEE 754 festgelegten einfachen (float) bzw doppelten (double) Genauigkeit für Gleitpunktwerte ermittelt werden. (s. Klassen-Modifizierer !) Alle innerhalb einer strictfp deklarierten Klasse vereinbarten Methoden sind implizit strictfp.
◇ Mehrere Methoden-Modifizierer dürfen – soweit sinnvoll – miteinander kombiniert werden. Allerdings ist nur jeweils ein Zugriffs-Spezifizierer zulässig. Ausserdem darf eine abstract vereinbarte Methode nicht gleichzeitig private, static, final oder native sein.
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 441 – 00 – TH – 03 ------------------------------------------------------------------------------------
Objekterzeugung in Java (1)
•••• Grundsätzliches
◇ Die Definition einer Objekt-Variablen erzeugt noch kein Objekt. Sie belegt lediglich Speicherplatz zur Aufnahme einer Objekt-Referenz.
◇ Objekte können in Java nur dynamisch auf dem Heap angelegt werden.
◇ Üblicherweise werden Objekte mittels eines new-Ausdrucks erzeugt. Ein new-Ausdruck wird aus dem new-Operator, dem Namen der zu instanzierenden Klasse und einer in runde Klammern eingeschlossenen Liste von Initialiserungswerten (� Parameter für den Konstruktor) gebildet. Die Liste der Initialisierungswerte kann auch leer sein, die runden Klammern müssen aber in jedem Fall angegeben werden.
◇ Ein new-Ausdruck
▻ bewirkt die Allokation von Speicher durch das Laufzeitsystem (JVM) für die Datenkomponenten des Objekts,
▻ initialisiert die Datenkomponenten
▻ und liefert nach Abschluß der Initialisierung eine Referenz auf das neu erzeugte Objekt zurück
◇ Die zurückgelieferte Referenz auf das erzeugte Objekt kann dann einer Objekt-Variablen passenden Typs zugewiesen werden. Sie kann gegebenenfalls auch als Referenz auf ein anonymes Objekt weiterverwendet werden, z.B. zum Aufruf von Memberfunktionen.
◇ Beispiel : Point pkt1; pkt1 = new Point(); pkt1.move(3.5, 4.7); Point pkt2 = (new Point()).move(-2.3, -1.7);
◇ Falls das Laufzeitsystem keinen ausreichenden Speicher allozieren kann, startet es den Garbage Collector, der versucht Speicher freizumachen. Falls auch danach nicht genügend freier Speicher für eine Allokation zur Verfügung steht, wird die Exception OutOfMemoryError geworfen.
◇ In Java sind noch weitere Mechanismen zur Objekterzeugung implementiert, u.a.
▻ Spezielle Generiermethoden (factory methods) im Rahmen des Reflection-APIs . Sie ermöglichen die Instan- zierung einer Klasse unter dynamischer Bereitstellung des Klassennamens als String. Dies erlaubt z.B. die Instanzierung einer Klasse, deren Name durch ein Programm erst eingelesen wird.
▻ Die clone()-Methode
▻ Implizite Objekterzeugung aus String-Konkatenationsausdrücken und Array-Initialisierern •••• Anmerkung zur Freigabe von Objekten
◇ Eine explizite Freigabe von Objekten ist nicht möglich. Die Freigabe nicht mehr referierter Objekte erfolgt vielmehr durch einen Garbage Collector, der als niederpriorer Hintergrund-Thread in der JVM läuft.
◇ Damit der Garbage Collector sinnvoll arbeiten kann, sollte die Referenz zu nicht mehr benötigten Objekten gegebe- nenfalls explizit aufgehoben werden, z.B. durch Zuweisung von null an die referierende Objekt-Variable. •••• Initialisierung von Objekten
◇ Die Datenkomponenten eines neu erzeugten Objekts werden durch das Laufzeitsystem (die JVM) initialisiert.
◇ Hierfür setzt die JVM die folgenden Mechanismen – falls vorhanden – in der angegebenen Reihenfolge ein :
▻ Initialisierung mit dem ihrem jeweiligen Typ entsprechenden Default-Wert.
▻ Initialisierung mittels den bei der Datenkomponenten-Definition angegebenen Initialisierern und durch Initialisierungsblöcke. Die Auswertung der Initialisierer und die Abarbeitung der Initialisierungsblöcke erfolgt in der Reihenfolge ihres Auftritts in der Klassendefinition.
▻ Initialisierung durch einen Konstruktor
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 442 – 00 – TH – 03 -----------------------------------------------------------------------------------
Objekterzeugung in Java (2) •••• Dynamische Bereitstellung des Namens der zu instanziierenden Klasse
◇ Die im Rahmen des Reflection-API bereitgestellten Bibliotheksklassen ermöglichen die Instanziierung von Klassen, deren Name erst dynamisch zu Laufzeit festgelegt wird.
◇ Die einfachste Möglichkeit hierfür erlaubt die Instanziierung von Klassen, die über einen Konstruktor ohne Para- meter (no-arg-Konstruktor) verfügen. Sie wird mittels Memberfunktionen der Klasse Class<T> (Package java.lang) realisiert.
◇ Die Klasse Constructor<T> (Package java.lang.reflect) ermöglicht darüberhinaus die Instanziierung von Klassen unter Verwendung parameterbehafteter Konstruktoren. Hierauf wird an dieser Stelle nicht eingegangen.
◇ Die Instanziierung einer Klasse, deren Name lediglich als String vorliegt, erfolgt in zwei Schritten :
▻ Ermittlung des Objekts der Klasse Class<T>, das die Klasse mit dem angegebenen Namen repräsentiert Der Typ-Parameter T steht für die repräsentierte Klasse (allgemein : den repräsentierten Typ)
▻ Erzeugung einer Instanz der durch das Class-Objekt repräsentierten Klasse.
◇ Ermittlung des eine Klasse repräsentierenden Class-Objekts : Mittels der statischen Memberfunktion der Klasse Class<T> : public static Class<?> forName(String name) throws ClassNotFoundException Diese Methode gibt eine Referenz auf das Objekt der Klasse Class<T> zurück, das die durch den vollqualifizier- ten Namen name bezeichnete Klasse repräsentiert (Objekt des Typs Class<name>). Wenn die zugehörige Klasse nicht gefunden wird, wird eine ClassNotFoundException geworfen.
◇ Instanziierung einer Klasse unter Verwendung ihres repräsentierenden Class-Objekts. Hierfür dient die nicht-statische Memberfunktion der Klasse Class<T> : public T newInstance() throws InstantationException, IllegalAccessException Diese Methode erzeugt ein neues Objekt der repräsentierten Klasse T, für das der no-arg-Konstruktor aufgerufen wird und gibt eine Referenz auf dieses Objekt zurück. Wenn die Klasse nicht instanziiert werden kann (z.B. abstrakte Klasse, Interface, Array, einfacher Datentyp, kein no-arg-Konstruktor vorhanden), wird eine InstantationException geworfen. Wenn die Klasse oder ihr no-arg-Konstruktor nicht zugreifbar ist, wird eine IllegalAccessException geworfen.
◇ Damit ein mittels newInstance() erzeugtes Objekt sinnvoll verwendet werden kann, muß es i.a. in seinen eigenen bzw in einen zuweisungskompatiblen Typ gecastet werden.
◇ Einfaches Demonstrationsbeispiel :
public class ObjErzeuger { public static void main(String[] args) { try { if (args.length==0) throw new RuntimeException("Programmparameter (Klassenname) fehlt"); Class<?> cl = Class.forName(args[0]); Object obj = cl.newInstance(); System.out.println("Erzeugtes Objekt Typ : " + obj.getClass().getName()); } catch (Exception e) { System.out.println(e); } } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 451 – 00 – TH – 03 -----------------------------------------------------------------------------------
Konstruktoren in Java (1)
•••• Allgemeines zu Konstruktoren
◇ Konstruktoren sind im Prinzip spezielle Memberfunktioen. Allerdings besitzen sie keinen Rückgabetyp und haben einen festgelegten Namen. In Java werden sie aber nicht zu den Memberfunktionen gerechnet.
◇ Konstruktoren sind nicht vererbbar und können damit weder überschrieben noch überdeckt werden.
◇ Konstruktoren werden implizit bei der Erzeugung eines Objekts zur Initialisierung seiner Datenkomponenten ausge- führt. Bei jeder Objekterzeugung wird genau ein Konstruktor durch das Laufzeitsystem aufgerufen. Sein Aufruf erfolgt nach einer Initialisierung der Datenkomponenten mit Defaultwerten und den Werten eventueller Initialisierer sowie nach der Abarbeitung eventueller Initialisierungsblöcke. Er kann gegebenenfalls weitere Konstruktoren explizit aufrufen.
◇ Konstruktoren können Parameter zur Festlegung der Initialisierungswerte für die Datenkomponenten besitzen. Eine Klasse kann mehrere Konstruktoren mit jeweils unterschiedlicher Parameterliste besitzen � Konstruktoren können überladen werden.
◇ Ein Konstruktor ohne Parameter wird in Java als no-arg constructor bezeichnet. •••• Definition von Konstruktoren
◇ Die Definition von Konstruktoren entspricht im wesentlichen der Definition von Memberfunktionen. Der Name eines Konstruktors muß gleich dem Klassennamen sein.
◇ Syntax :
◇ Als Konstruktor-Modifizierer sind nur die Zugriffs-Spezifizierer public, protected und private zulässig.
◇ Konstruktoren können auch Exceptions werfen. Geprüfte Exceptions sind in einer throws-Klausel zu deklarieren. Wirft ein Konstruktor eine Exception, wird der den Konstruktoraufruf veranlassende new-Ausdruck durch Werfen der Exception beendet. Eine Referenz auf das neu erzeugte Objekt wird nicht zurückgegeben.
◇ Ist in einer Klassendefinition kein Konstruktor explizit festgelegt, wird vom Compiler implizit ein Konstruktor ohne Parameter (no-arg constructor) erzeugt � Default-Konstruktor. Die einzige Funktionalität dieses Konstruktors besteht im Aufruf des no-arg-Konstruktors der Basisklasse. Er besitzt die gleiche Zugriffsberechtigung , die für die Klasse festgelegt ist.
◇ In Java kann ein Konstruktor andere Konstruktoren der gleichen Klasse (andere Parameterliste) aufrufen � Verkettung von Konstruktoren. Zum Aufruf eines anderen Konstruktors dient die this-Referenz, der in runden Klammern die aktuelle Parameter- liste nachzustellen ist. Ein derartiger expliziter Konstruktoraufruf muß die erste Anweisung im aufrufenden Konstruktor sein.
◇ Copy-Konstruktoren sind auch möglich. Allerdings sind sie in Java weniger gebräuchlich. Zur Erzeugung der Kopie eines Objekts wird i.a. die – in der Klasse Object definierte und in anderen Klassen geeignet zu überladene – clone()-Methode bevorzugt.
◇ Ein Konstruktor kann auch eine Typ-Param-Deklaration besitzen, d.h. mit formalen Typ-Parametern definiert werden (unabhängig davon, ob die Klasse generisch ist) � generischer Konstruktor
Konstruktor-Kopf
Konstruktor-Rumpf
( Klassen-Name Formal-Parameterliste )
Anweisung { }
Konstruktor- Modifizierer
Typ-Param-
Deklaration throws-Klausel
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 452 – 00 – TH – 02 -----------------------------------------------------------------------------------
Konstruktoren in Java (2)
•••• Beispiel :
// CelBody.java public class CelBody { private long idNum; private String name = "<unbekannt>"; private CelBody orbits; private static long nextID = 1; public CelBody() { System.out.println(toString()); idNum = nextID++; } public CelBody(String bName, CelBody orbAround) { this(); name = bName; orbits = orbAround; System.out.println(toString()); } public CelBody(String bName) { this(bName, null); } public String toString() { StringBuffer sb = new StringBuffer("Name : "); sb.append(name).append(" ID : ").append(idNum); sb.append(" orbits around : ").append((orbits==null) ? "null" : orbits.name); sb.append(" next ID : ").append(nextID); return new String(sb); } public CelBody getOrbits() { return orbits; } // ... public static void main(String[] args) { CelBody sonne = new CelBody("Sun"); CelBody erde = new CelBody("Earth", sonne); CelBody mond = new CelBody("Moon", erde); // ... } }
Name : <unbekannt> ID : 0 orbits around : null next ID : 1 Name : Sun ID : 1 orbits around : null next ID : 2 Name : <unbekannt> ID : 0 orbits around : null next ID : 2 Name : Earth ID : 2 orbits around : Sun next ID : 3 Name : <unbekannt> ID : 0 orbits around : null next ID : 3 Name : Moon ID : 3 orbits around : Earth next ID : 4
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 453 – 00 – TH – 04 ------------------------------------------------------------------------------------
Initialisierungsblöcke in Java (1)
•••• Allgemeines
◇ Innerhalb Klassendefinitionen können auch sogenannte Initialisierungsblöcke definiert werden.
◇ Initialisierungsblöcke sind in das Klammerpaar { und } eingeschlossene Anweisungsfolgen, die ausserhalb jeder Memberfunktion stehen.
◇ Sie stellen eine Erweiterung der (Feld-)Initialisierer dar und ermöglichen eine komplexe nicht-triviale Initialisierung der Datenkomponenten einer Klasse.
◇ Sie werden konkurierend zu der Auswertung der (Feld-)Initialisierer ausgeführt, wobei sich die Reihenfolge nach der Auftritts-Reihenfolge in der Klassendefinition richtet.
◇ Einem Initialisierungsblock können keine Parameter übergeben werden.
◇ Ein Initialisierungsblock darf keine return-Anweisung enthalten (� Compiler-Fehler).
◇ Obwohl für die Initialisierung von Datenkomponenten vorgesehen, kann ein Initialisierunsgblock prinzipiell beliebigen Code ausführen.
◇ Es gibt
▻ Objekt-Initialisierungsblöcke (instance initializer) und
▻ Klassen-Initialisierungsblöcke (statische Initialisierungsblöcke, static initializer) •••• Objekt-Initialisierungsblöcke (instance initializer)
◇ Objekt-Initialisierungsblöcke werden bei jeder Instanzierung der Klasse ausgeführt. Sie sollen zur Initialisierung der objektspezifischen Datenkomponenten (Instanz-Variablen) dienen.
◇ Mehrere Objekt-Initialisierungsblöcke werden zusammen mit eventuellen Initialisierern für die Instanz-Variablen in der Reihenfolge ihres Auftritts in der Klassendefinition zu einer einzigen Initialisierungsroutine zusammengefasst. Diese wirkt so, als ob sie zu Beginn jedes Konstruktors der Klasse stehen würden.
◇ Objekt-Initialisierungsblöcke können das aktuelle Objekt mittels der this-Referenz referieren.
◇ Ein Objekt-Initialisierungsblock darf nur dann eine geprüfte Exception werfen, wenn alle Konstruktoren diese Exception (oder eine ihrer Basisklassen) als werfbar deklariert haben.
◇ Objekt-Initialisierungsblöcke lassen sich sinnvoll als Ersatz von no-arg-Konstruktoren einsetzen, wenn deren Funktio- nalität in jedem anderen Konstruktor verwendet werden soll (expliziter Aufruf des no-arg-Konstruktors), der no-arg- Konstruktor für die Objekt-Erzeugung aber direkt nicht benötigt wird.
◇ Beispiel :
public class CelBody2 { private long idNum; private String name ; private CelBody2 orbits; private static long nextID = 1; { // Objekt-Initialisierungsblock name = "<unbekannt>";
System.out.println(toString());
idNum = nextID++;
}
public CelBody2(String bName, CelBody2 orbAround)
{ name = bName; orbits = orbAround; System.out.println(toString()); } // ... }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 454 – 00 – TH – 01 -----------------------------------------------------------------------------------
Initialisierungsblöcke in Java (2) •••• Klassen-Initialisierungsblöcke (static initializer)
◇ Klassen-Initialisierungsblöcke werden nur einmal beim Laden einer Klasse in die JVM ausgeführt. Sie sollen zur Initialisierung der klassenspezifischen (statischen) Datenkomponenten (Klassen-Variablen) dienen.
◇ Syntax :
◇ Mehrere Klassen-Initialisierungsblöcke werden zusammen mit eventuellen Initialisierern für die Klassen-Variablen in der Reihenfolge ihres Auftritts in der Klassendefinition zu einer einzigen Initialisierungsroutine zusammengefasst. Diese kann im Prinzip als eine Art "Klassen-Konstruktor" aufgefasst werden.
◇ Ein Klassen-Initialisierungsblock kann nur statische Komponenten seiner Klasse referieren.
◇ Ein Klassen-Initialisierungsblock darf keine geprüften Exceptions werfen.
◇ Beispiele für Anwendungen :
▻ Initialisierung von statischen Datenkomponenten, deren Wertermittlung komplexerer Natur ist. Häufig handelt es sich hierbei um den Aufbau von Tabellen (z.B. Codetabellen, Tabellen mathematischer Funktionswerte usw).
▻ Einlesen von in Maschinencode vorliegenden Bibliotheks-Routinen, die native-Methoden implementieren (durch Aufruf von System.load(...) bzw System.loadLibrary()).
◇ Beispiel :
Anweisung { } static
public class Circle { // Lookup-Tabellen fuer sin- und cosin-Werte static private final int NUM_VALS = 1000; static private double sines[] = new double[NUM_VALS]; static private double cosines[] = new double[NUM_VALS]; // Klassen-Initialisierungsblock zum Fuellen der Lookup-Tabellen static {
double x, deltaX;
int i;
deltaX = (Math.PI/2)/(NUM_VALS-1);
for (i=0, x = 0.0; i < NUM_VALS; i++, x += deltaX)
{ sines[i] = Math.sin(x);
cosines[i] = Math.cos(x);
}
System.out.println("Lookup-Tabellen initialisiert !"); }
// ... public static void main(String[] args) { System.out.println("Klasse Circle wird verwendet !"); } }
Lookup-Tabellen initialisiert ! Klasse Circle wird verwendet !
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 461 – 00 – TH – 03 -----------------------------------------------------------------------------------
Vererbung in Java (1)
•••• Prinzip und Eigenschaften
◇ Eine Klasse kann durch Vererbung erweitert (extended, subclassed) werden � Definition einer abgeleiteten Klasse. Die abgeleitete Klasse (subclass, extended class) erbt alle Datenkomponenten und Memberfunktionen ihrer Basis- klasse (superclass) Sie kann neue Datenkomponenten und Methoden hinzufügen. � Ergänzung / Änderung des Verhaltens der Klasse
◇ Die in der abgeleiteten Klasse neu definierten Komponenten können den gleichen Namen wie Komponenten der Basisklasse tragen. In einem derartigen Fall werden die gleichnamigen Komponenten der Basisklasse entweder überdeckt oder überschrieben oder überladen.
◇ Von einer als final vereinbarten Klasse können keine weiteren Klassen abgeleitet werden.
◇ In Java hat jede Klasse, die nicht explizit von einer anderen Klasse abgeleitet ist, die Klasse Object als direkte Basisklasse.
◇ Da in Java nur einfache Vererbung möglich ist, besitzt jede Klasse – außer der Klasse Object – genau eine Basis- klasse.
◇ Ein Objekt einer abgeleiteten Klasse kann überall verwendet werden, wo ein Objekt der Basisklasse benötigt wird. � Referenzvariable einer Basisklasse können auch auf Objekte abgeleiteter Klassen zeigen. � Polymorphie. Abgeleitete Klassen sind zuweisungs-kompatibel zu ihren Basisklassen.
◇ In jedem Objekt einer abgeleiteten Klasse steht mit dem Schlüsselwort super eine Referenz auf das in ihm enthal- tene Basisklassen-Teilobjekt zur Verfügung. Mittels der super-Referenz können nur Komponenten der Basisklasse angesprochen sowie Basisklassen-Kon- struktoren aufgerufen werden. Sie kann nicht – wie this – allein benutzt werden, um das Basisklasen-Teilobjekt insgesamt anzusprechen. •••• Syntax zur Angabe der Basisklasse in der Klassendefinition (extends-Deklaration) Klassen-Ableitung :
•••• Konstruktoren von abgeleiteten Klassen
◇ Ein Konstruktor kann nur die Datenkomponenten der eigenen Klasse initialisieren. Die Initialisierung der geerbten Datenkomponenten der Basisklasse muß durch einen Konstruktor der Basisklasse erfolgen.
◇ Jeder Aufruf eines Konstruktors muß daher als erstes den Aufruf eines Konstruktors der Basisklasse bewirken. Dies kann erfolgen durch :
▻ den expliziten Aufruf eines Basisklassen-Konstruktors mittels super(...). Dieser Aufruf muß die erste Anweisung im Konstruktor der abgeleiteten Klasse sein
▻ den indirekten Aufruf eines Basisklassen-Konstruktors über den Aufruf eines anderen Konstruktors der abge- leiteten (also der eigenen) Klasse mittels this(...). Der Aufruf this(...) muß die erste Anweisung im Konstruktor der abgeleiteten Klasse sein.
▻ den impliziten Aufruf des no-arg-Konstruktors der Basisklasse, wenn die erste Anweisung im Konstruktor der abgeleiteten Klasse weder super(...) noch this(...) ist.
◇ Nach der Abarbeitung des Basisklassen-Konstruktors werden zunächst die Initialisierer der Instanz-Variablen und die Objekt-Initialisierungsblöcke der eigenen (abgeleiteten) Klasse ausgewertet. Erst danach werden die – übrigen – Anweisungen im Rumpf des Konstruktors ausgeführt.
◇ Anmerkung : In den Parameter-Ausdrücken eines expliziten Konstruktorsaufrufs (mittels super(...) oder this(...)) darf keine Komponente des aktuellen Objekts referiert werden.
Basisklassenname extends
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 462 – 00 – TH – 02 -----------------------------------------------------------------------------------
Vererbung in Java (2)
•••• Überschreiben von Methoden (Overriding)
◇ Eine in der abgeleiteten Klasse definierte Methode mit gleichem Namen und gleicher Parameterliste ( == gleicher Signatur) sowie gleichem Rückgabetyp wie in der Basisklasse, überschreibt die Methode der Basisklasse. Hierdurch wird die Basisklassen-Implementierung der Methode für die abgeleitete Klasse durch eine neue Imple- mentierung ersetzt.
◇ Handelt es sich bei der überschriebenen Funktion um eine abstrakte Methode (Deklaration als abstract), so wird sie durch die überschreibende Funktion erst implementiert.
◇ Ausnahme von der Gleichheit der Parameterlisten : Parameter dürfen sich in der final-Eigenschaft unterscheiden.
◇ Die Definition einer Methode in der abgeleiteten Klasse, die sich nur im Rückgabetyp von einer Methode gleichen Namens in der Basisklasse unterscheidet, ist ein Fehler.
◇ Es können nur Methoden überschrieben werden, die weder als static noch als private noch als final vereinbart sind. � In Java ist jede nichtstatische Methode der Basisklasse, die nicht private oder final ist, grundsätzlich virtuell.
◇ Beim Aufruf einer derartigen Methode über eine Basisklassen-Referenz wird die in der tatsächlichen Klasse des aktuell referierten Objekts definierte Methode ausgeführt (� late binding, Polymorphie !)
◇ Eine in der abgeleiteten Klasse definierte überschreibende Funktion darf die in der Basisklasse festgelegte Zugriffs- berechtigung nicht einschränken. Eine Erweiterung der Zugriffsberechtigung ist zulässig. Beispiel : Wenn in der Basisklasse für eine Methode protected festgelegt ist, darf eine überschreibende Methode in der abgeleiteten Klasse protected oder public sein, jedoch nicht private oder package.
◇ Die übrigen Methoden-Modifizierer dürfen wie folgt verändert werden :
▻ synchronized, native und strictfp können beliebig verändert (entfernt oder hinzugefügt) werden
▻ abstract kann entfernt oder hinzugefügt werden.
▻ eine überschreibende Methode kann final gemacht werden.
▻ eine überschreibende Methode kann nicht static sein.
◇ Bezüglich der Exception-Deklaration (throws-Klausel) gelten folgende Regeln :
▻ Die Exception-Deklarationen von überschreibender und überschriebener Methode können unterschiedlich sein.
▻ Eine überschreibende Methode darf in ihrer Exception-Deklaration nur Exception-Typen enthalten, die zu einem in der Exception-Deklaration der überschriebenen Methode festgelegten Typen polymorph kompatibel (d.h. von der gleichen Klasse oder einer von ihr abgeleiteten Klasse) sind.
▻ Eine überschreibende Methode muss nicht alle von der überschriebenen Methode deklarierten Exception-Typen ebenfalls deklarieren. Auch wenn die überschriebene Methode eine Exception-Deklaration hat, darf diese bei der überschreibenden Methode fehlen.
▻ Eine überschreibende Methode darf nichtgeprüfte Exceptions werfen, die in der überschriebenen Methode nicht auftreten können. Diese dürfen aber nicht in die Exception-Deklaration aufgenommen werden.
◇ Zu der überschriebenen Methode kann – innerhalb der überschreibenden Methode oder in einer anderen Instanz- Methode der gleichen Klasse – über die Basisklassen-Teilobjekt-Referenz super zugegriffen werden. super.method(...) ruft immer die Implementierung der Methode method(...) auf, die in der direkten Basisklasse verwendet wird. Es kann sich dabei durchaus um eine Methode handeln, die in der Ableitungshierarchie "weiter oben" definiert und in der direkten Basisklasse selbst nicht neu definiert worden ist.
◇ Ein Zugriff zur überschriebenen Methode über ihren vollqualifizierten Namen ist nicht möglich (� Compiler-Fehler).
◇ Ein Cast einer Referenz auf ein Objekt der abgeleiteten Klasse in die Basisklassen-Referenz ändert nicht den tatsäch- lichen Typ des referierten Objekts. Über einen derartigen Cast kann daher nicht zur überschriebenen sondern nur zur überschreibenden Methode zugegriffen werden.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 463 – 00 – TH – 02 -----------------------------------------------------------------------------------
Vererbung in Java (3) •••• Überladen von Methoden (Overloading)
◇ Eine in der abgeleiteten Klasse definierte Methode mit gleichem Namen aber anderer Parameterliste, überlädt die Methode der Basisklasse. Der Rückgabetyp bleibt unberücksichtigt, er kann gleich oder unterschiedlich sein. Das gleiche gilt für die Exception-Deklaration (throws-Klausel).
◇ In der abgeleiteten Klasse kann sowohl zu der geerbten Methode der Basisklasse als auch zu der neu definierten Methode allein über ihren Namen zugegriffen werden. � in Java ist – anders als in C++ – ein Überladen von Methoden auch über Klassengrenzen hinweg möglich.
◇ Zusätzlich können Methoden natürlich auch innerhalb einer Klasse überladen werden.
◇ Wenn in der Basisklasse zwei Methoden überladen sind, ist es möglich, dass nur eine der Methoden in einer abgelei- teten Klasse überschrieben wird. Die andere steht dann auch in der abgeleiteten Klasse als überladene Funktion zur Verfügung. � Das Überschreiben von Methoden erfolgt auf der Basis der Signaturen. C++ verhält sich in einem derartigen Fall anders : Durch das Überschreiben einer Methode werden sämtliche weiteren überladenen Methoden der Basisklasse überdeckt.
◇ Auch statische Methoden können im obigen Sinn überladen werden.
◇ Ferner können statische Methoden nicht-statische Methoden und umgekehrt überladen. •••• Überdecken von Klassenkomponenten (Hiding)
◇ Statische Methoden können überdeckt statt überschrieben werden. Eine in der abgeleiteten Klasse definierte statische Methode mit gleicher Signatur sowie gleichen Rückgabetyps wie eine statische Methode der Basisklasse, überdeckt die Methode der Basisklasse.
◇ Eine statische Methode darf keine Instanz-Methode überdecken (� Compiler-Fehler)
◇ Überdecken von Datenkomponenten ist zulässig
▻ zwischen Instanz-Variablen (nicht-statischen Datenkomponenten)
▻ zwischen Klassen-Variablen (statischen Datenkomponenten)
▻ gemischt zwischen Instanz- und Klassen-Variablen.
◇ Das Überdecken zwischen Datenkomponenten unterschiedlichen Typs ist zulässig.
◇ Überdeckt werden genaugenommen Namen. Überdecken eines Namens bedeutet, dass in der abgeleiteten Klasse der Name allein nur in der in dieser Klasse defi- nierten Bedeutung verwendet werden kann. Um den Namen in der Bedeutung, die in der Basisklasse definiert ist, zu verwenden, muss der entsprechende voll- qualifizierte Name oder der Name zusammen mit einer anderen Basisklassen-Referenz (z.B. super.kompo, innerhalb einer Instanz-Methode) verwendet werden. Die Verwendung des vollqualifizierten Namens ist nur für statische Komponenten zulässig.
◇ Beim Zugriff zu überdeckten Komponenten wird die tatsächlich ausgewählte Komponente durch die deklarierte Klasse der verwendeten Referenz (und nicht durch die Klasse des referierten Objekts) festgelegt. (Festlegung zur Compile-Zeit, early binding)
◇ Zwischen einer Variablen und einer Funktion gleichen Namens findet kein Überdecken statt. Beide können gleichzeitig allein mit ihrem Namen verwendet werden. Das gilt auch, wenn beide in derselben Klasse definiert sind.
◇ Eine als private deklarierte Komponente kann weder überschrieben noch überdeckt werden (Sie ist ja in der abgeleiteten Klasse überhaupt nicht zugänglich). Ihr Name kann deshalb in der abgeleiteten Klasse für beliebige Definitionen verwendet werden. Beispielsweise ist es bei einer Memberfunktion zulässig, in der abgeleiteten Klasse eine Methode mit gleicher Signatur aber unterschiedlichem Rückgabetyp zudefinieren.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 464 – 01 – TH – 01 -----------------------------------------------------------------------------------
Vererbung in Java (4-1) •••• Demonstrationsbeispiel zum Überschreiben und Überladen von Methoden
◇ Definition einer Basisklasse Punkt
◇ Definition einer abgeleiteten Klasse Farbpunkt
public class Farbpunkt extends Punkt { private String col; public Farbpunkt() { this("black"); } public Farbpunkt(String wcol) { super(); col = wcol; } public Farbpunkt(double wx, double wy) { this(wx, wy, "black"); } public Farbpunkt(double wx, double wy, String wcol) { super(wx, wy); col = wcol; } public Farbpunkt change(String ncol) // ueberlaedt Basisklassenmethode { col = ncol; return this; } public Farbpunkt change(Farbpunkt fp) // ueberlaedt Basisklassenmethode { change((Punkt)fp); change(fp.col); return this; } public String toString() // ueberschreibt Basisklassenmethode { StringBuffer hb = new StringBuffer(super.toString()); hb.append(" & ").append(col); return new String(hb); }
public class Punkt { private double x = 0.0; private double y = 0.0; public Punkt() { } public Punkt(double wx, double wy) { x = wx; y = wy; } public Punkt move(double dx, double dy) { x += dx; y += dy; return this; } public Punkt change(Punkt p) { x = p.x; y = p.y; return this; } public String toString() { StringBuffer hb = new StringBuffer(); hb.append('(').append(x).append(" , ").append(y).append(')'); return new String(hb); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 464 – 02 – TH – 01 -----------------------------------------------------------------------------------
Vererbung in Java (4-2) •••• Demonstrationsbeispiel zum Überschreiben und Überladen von Methoden, Forts
◇ Definition einer verwendenden Test-Klasse PunktTest
◇ Ausgabe des Demonstrations-Programms
// PunktTest.java public class PunktTest { public static void main(String[] args) { Punkt p1 = new Punkt(4.2, 6.3); Punkt p2 = new Farbpunkt(); Farbpunkt p3 = new Farbpunkt(1.8, 7.9); Punkt p4 = new Farbpunkt("magenta"); Farbpunkt p5 = new Farbpunkt(2.5, 3.7, "blue"); System.out.println("p1 : " + p1); System.out.println("p2 : " + p2); System.out.println("p3 : " + p3); System.out.println("p4 : " + p4); System.out.println("p5 : " + p5); System.out.println("nach einigen Aenderungen : "); p3.move(1.0, 1.0); System.out.println("p3 : " + p3); p3.change("yellow"); System.out.println("p3 : " + p3); p5.change(p1); System.out.println("p5 : " + p5); p3.change(p5); System.out.println("p3 : " + p3); } }
p1 : (4.2 , 6.3) p2 : (0.0 , 0.0) & black p3 : (1.8 , 7.9) & black p4 : (0.0 , 0.0) & magenta p5 : (2.5 , 3.7) & blue nach einigen Aenderungen : p3 : (2.8 , 8.9) & black p3 : (2.8 , 8.9) & yellow p5 : (4.2 , 6.3) & blue p3 : (4.2 , 6.3) & blue
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 465 – 00 – TH – 01 -----------------------------------------------------------------------------------
Vererbung in Java (5) •••• Demonstrationsbeispiel zum Überdecken und Überladen von statischen Methoden
◇ Definition einer Basisklasse Ober2
◇ Definition einer abgeleiteten Klasse Unter2
◇ Ausgabe des Demonstrations-Programms
class Ober2 { public static String gruss() { return "sagt Hallo !"; } public String name() { return "Ober2 "; } }
class Unter2 extends Ober2 { public static String gruss() // ueberdeckt Basisklassen-Methode { return "sagt Guten-Morgen !"; } public static String gruss(String gr) // ueberlaedt Basisklassen-Methode { return "sagt " + gr; } public String name() // ueberschreibt Basisklassen-Methode { return "Unter2 "; } public static void main(String[] args) { Ober2 s = new Ober2(); System.out.println(s.name() + s.gruss()); s = new Unter2(); System.out.println(s.name() + s.gruss()); Unter2 u = new Unter2(); System.out.println(u.name() + u.gruss()); System.out.println(u.name() + u.gruss("Servus !")); System.out.println(u.name() + gruss()); System.out.println(u.name() + Ober2.gruss()); } }
Ober2 sagt Hallo ! Unter2 sagt Hallo ! Unter2 sagt Guten-Morgen ! Unter2 sagt Servus ! Unter2 sagt Guten-Morgen ! Unter2 sagt Hallo !
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 466 – 00 – TH – 01 -----------------------------------------------------------------------------------
Vererbung in Java (6) •••• Demonstrationsbeispiel zum Überdecken von Datenkomponenten
◇ Definition einer Basisklasse Ober3
◇ Definition einer abgeleiteten Klasse Unter3
◇ Ausgabe des Demonstrations-Programms
class Ober3 { protected int meinW = 125; protected static float deinW = 6.35f; protected int val = 23; }
class Unter3 extends Ober3 { private static double meinW = 3.5; private float deinW = 5.2f; public int val() { return val; } public void nutzeWerte() { System.out.println("in Unter3 : meinW " + meinW + " deinW " + deinW); System.out.print( "in Ober3 : meinW " + super.meinW); System.out.println(" deinW " + super.deinW); System.out.print( "in Ober3 : meinW " + super.meinW); System.out.println(" deinW " + Ober3.deinW); } public static void main(String[] args) { Unter3 u = new Unter3(); u.nutzeWerte(); System.out.println(); System.out.println("val direkt : " + u.val); System.out.println("val ueber Fkt : " + u.val()); } }
in Unter3 : meinW 3.5 deinW 5.2 in Ober3 : meinW 125 deinW 6.35 in Ober3 : meinW 125 deinW 6.35 val direkt : 23 val ueber Fkt : 23
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 467 – 00 – TH – 02 -----------------------------------------------------------------------------------
Vererbung in Java (7) •••• Typkompatibilität und -umwandlung
◇ Eine abgeleitete Klasse ist zuweisungs-kompatibel zu ihrer Basisklasse. � Einer Basisklassen-Variablen kann jederzeit eine Referenz auf ein Objekt einer von der Basisklasse abgeleiteten Klasse zugewiesen werden.
◇ Das durch eine Basisklassen-Variable referierte Objekt einer abgeleiteten Klasse wird dadurch als Objekt der Basisklasse behandelbar. � Implizite Typumwandlung. Da von einem spezialisierteren Typ in einen allgemeineren Typ umgewandelt wird, spricht man auch von einer erweiternden Typumwandlung (widening conversion). Weil diese Umwandlung in der Klassen-Hierarchie aufwärts erfolgt nennt man sie auch Aufwärts-Cast (upcast).
◇ Die Zuweisung einer Basisklassen-Referenz, die aber tatsächlich auf ein Objekt einer abgeleiteten Klasse zeigt, an eine Variable des tatsächlich referierten Typs ist nicht implizit möglich. Sie erfordert eine explizite Typumwandlung mittels des Cast-Operators. Hierbei findet eine Umwandlung von einem allgemeineren Typ in einen spezialisierteren Typ statt. Man nennt dies eine einengende Typumwandlung (narrowing conversion) oder einen Abwärts-Cast (down cast).
◇ Ein Abwärts-Cast ist prinzipiell unsicher. Er darf nur dann durchgeführt werden, wenn durch die Basisklassen-Referenz tatsächlich ein Objekt des angege- benen Zieltyps referiert wird. Der Versuch einer Typumwandlung, bei der dies nicht erfüllt ist, führt zum Werfen einer Exception vom Typ ClassCastException. •••• Der Operator instanceof
◇ Dieser binäre Operator ermöglicht die Überprüfung, ob ein Ausdruck zuweisungskompatibel zu einem bestimmten Typ ist.
◇ Syntax :
◇ Wert eines instanceof-Ausdrucks :
▻ true, wenn der Ausdruck der linken Seite zuweisungs-kompatibel zum Typ der rechten Seite ist
▻ false, wenn der Ausdruck der linken Seite nicht zuweisungs-kompatibel zum Typ der rechten Seite ist
◇ Der instanceof-Operator kann eingesetzt werden, um einen sicheren Abwärts-Cast zu ermöglichen.
◇ Beispiel :
Typangabe instanceof Ausdruck
class That { // ... } class More extends That { // ... } // ... That sref = new More(); More mref; // ... if (sref instanceof More) mref=(More)sref; // ...
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 471 – 00 – TH – 04 -----------------------------------------------------------------------------------
Interfaces in Java (1)
•••• Prinzip
◇ Interfaces definieren – ähnlich wie Klassen – Typen. Allerdings erfolgt die Definition in einer abstrakten Form, die keinerlei Implementierung bereitstellt. Damit lassen sich Interfaces nicht instanziieren. Sie legen – wie der Name bereits ausdrückt – lediglich eine Schnittstelle (Kontrakt) fest, die dann von Klassen imple- mentiert werden kann.
◇ Ein Interface besteht – ähnlich wie eine Klasse – aus Komponenten. Diese Komponenten können aber lediglich sein :
▻ abstrakte Methoden
▻ Konstante
▻ eingebettete Klassen und Interfaces
◇ Im Prinzip ähnelt ein Interface einer abstrakten Klasse. Im Unterschied zu einem Interface kann eine abstrakte Klasse aber eine (Teil-) Implementierung enthalten. (Instanz- und Klassen-Variable, Klassen-Methoden, definierte Instanz-Methoden). Ein Interface kann als abstrakte Klasse, die nur Konstante und abstrakte Methoden (und gegebenenfalls eingebettete Typen) vereinbart, aufgefasst werden ("rein abstrakte" Klasse).
◇ Interfaces müssen wie Klassen in jeweils einer eigenen Quelldatei (Ausnahme eingebettete Interfaces) definiert werden, deren Hauptname gleich dem Interface-Namen sein muß. Interfaces werden vom Compiler auch getrennt übersetzt.
•••• Interface-Definition
◇ Syntax :
◇ Beispiel :
public interface Fahrbar { int MOTOR_UND_REIFEN = 3; int MOTOR_UND_SCHRAUBE = 5; int MUSKEL_UND_REIFEN = 2; int MUSKEL_UND_SCHRAUBE = 4; int LEHRLAUF = 0; void setAntrieb(int antr); void fahreVor(double dist); void fahreRueck(double dist); int getAntrieb(); double getFahrZaehler(); }
;
{ Konstantendefinition
Abstrakte-Methoden-Deklaration
}
Klassen-/Interface-Definition
interface Interface-Name
Interface-
Ableitung
Interface- Modifizierer
Typ-Param-
Deklaration
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 472 – 00 – TH – 04 -----------------------------------------------------------------------------------
Interfaces in Java (2)
•••• Interface-Modifizierer
◇ Zulässig sind :
▻ public Ohne diesen Zugriffs-Spezifizierer besitzt jedes Interface die Zugrifssberechtigung package.
▻ abstract Jedes Interface ist implizit abstract. Eine explizite Angabe dieses Modifizierers ist daher überflüssig. In der Sprachspezifikation ist sie als "überholt" (obsolete) bezeichnet und sollte daher nicht verwendet werden.
▻ strictfp Alle Floating-Point-Ausdrücke innerhalb der Interface-Definition (z.B. zur Konstanten-Initialisierung bzw innerhalb eingebetteter Typen) werden FP-strict ausgewertet
◇ Für Interfaces, die innerhalb von Klassen oder anderen Interfaces definiert sind (eingebettete Interfaces, member
interfaces) sind darüber hinaus auch zulässig :
▻ protected
▻ private
▻ static
•••• Definition von Memberkonstanten (Interface-Konstante)
◇ Ein Interface darf als Datenkomponenten nur Konstante enthalten.
◇ Jede Datenkomponente ist daher implizit static und final. Zusätzlich ist sie implizit public. Eine explizite Angabe dieser Feld-Modifizierer ist zwar zulässig, aber überflüssig.
◇ Jede Datenkomponente muß durch einen Initialisierer initialisiert werden. � blank finals sind nicht zulässig. Der Initialisierer muß ein konstanter Ausdruck sein. Dieser Ausdruck darf weder den Namen der zu initialisierenden Komponente noch einer Komponente, die erst später definiert wird, enthalten � Compiler-Fehler.
◇ Beispiel :
•••• Deklaration abstrakter Memberfunktionen (Interface-Methoden)
◇ Jede in einer Interface-Definition enthaltene Memberfunktion ist implizit abstract. Ihre Vereinbarung muß an Stelle eines Funktionsrumpfes ein ; enthalten.
◇ Jede in einer Interface-Definition enthaltene Memberfunktion ist implizit public. Nichtöffentliche Memberfunktionen machen keinen Sinn.
◇ Eine explizite Verwendung der Modifizierer abstract und public ist zwar zulässig, aber überflüssig und sollte vermieden werden.
◇ Andere Modifizierer sind unzulässig. Allerdings dürfen die in implementierenden Klassen enthaltenen Definitionen der Interface-Methoden mit den Modifiern strictfp, native, synchronized und final versehen werden.
interface Test { float f = j; // Compiler-Fehler ! int j = 1; int k = k + 1; // Compiler-Fehler ! }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 473 – 00 – TH – 04 -----------------------------------------------------------------------------------
Interfaces in Java (3)
•••• Vererbung von Interfaces
◇ Interfaces können auch voneinander abgeleitet werden
◇ Es gibt aber kein allgemeines Wurzel-Basis-Interface (etwa wie die Wurzel-Basisklasse Object)
◇ Im Unterschied zu Klassen ist bei Interfaces Mehrfachvererbung zulässig. � Ein Interface kann von mehreren anderen Interfaces abgeleitet sein.
◇ Syntax : Interface-Ableitung :
◇ Beispiel : Bibliotheks-Interfaces Serializable (Package java.io) Runnable (Package java.lang) public Interface SerializeAndRunnable extends java.io.Serializable, Runnable { // ... } Das Interface SerializeAndRunnable enthält – durch Vererbung – alle Komponenten der Interfaces Serializable und Runnable. Zusätzlich kann es weitere Komponenten definieren.
◇ Bei abgeleiteten Interfaces kann ebenfalls Überschreiben, Überladen und Überdecken von Komponenten auftreten. Prinzipiell gelten hierfür die gleichen Regeln und Einschränkungen wie bei abgeleiteten Klassen :
▻ Überschreiben von Memberfunktionen : Die Deklaration einer Memberfunktion in einem abgeleiteten Interface überschreibt alle geerbten Memberfunktionen mit gleicher Signatur (gleicher Name und gleiche Parameterliste) und gleichem Rückgabetyp. Eine tatsächliche Auswirkung hat ein derartiges Überschreiben nur, wenn dadurch im abgeleiteten Interface eine Einschränkung in der Exception-Deklaration (throws-Klausel) der Methode vorgenommen wird (s. Vererbung bei Klassen).
▻ Die Deklaration einer Memberfunktion in einem abgeleiteten Interface mit gleicher Signatur aber unterschied- lichem Rückgabetyp wie in einem Basis-Interface ist unzulässig und führt zu einem Compilerfehler. Gleiches gilt, wenn zwei Methoden mit gleichem Namen und gleicher Signatur aber unterschiedlichen Rückgabe- typen – von unterschiedlichen Basis-Interfaces – geerbt werden.
▻ Überladen von Memberfunktionen : Die Deklaration einer Memberfunktion in einem abgeleiteten Interface überlädt alle geerbten Memberfunktionen mit gleichem Namen aber unterschiedlicher Parameterliste. Der Rückgabetyp und die Exception-Deklaration bleiben unberücksichtigt. Überladen liegt auch vor, wenn innerhalb desselben Interfaces Methoden mit gleichem Namen aber unterschied- licher Parameterliste deklariert werden oder wenn alle derartigen Methoden von Basis-Interfaces geerbt werden.
▻ Überdecken von Datenkomponenten (Konstanten) Die Definition einer Konstanten in einem abgeleiteten Interface überdeckt jede geerbte Konstante gleichen Namens, unabhängig vom jeweiligen Typ. Der Zugriff zur geerbten Konstanten ist nur über deren vollqualifizierten Namen möglich.
◇ Erbt ein Interface von zwei verschiedenen Basis-Interfaces zwei Methoden gleicher Signatur und gleichem Rückgabe- typ, so "verschmelzen" diese im abgeleiteten Interface zu einer einzigen Methode.
◇ Erbt ein Interface von zwei verschiedenen Basis-Interfaces zwei Konstante gleichen Namens, so kann zu Ihnen – unabhängig von ihrem jeweiligen Typ – nur über ihren vollqualifizierten Namen zugegriffen werden.
◇ Es ist auch zulässig, dass ein Interface dieselbe Methode bzw Konstante auf verschiedenen Ableitungswegen erbt. Die Methode bzw die Konstante ist in dem abgeleiteten Interface nur einmal vorhanden. Ein Zugriff ist eindeutig.
Basis-Interface-Name extends
,
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 474 – 00 – TH – 06 ------------------------------------------------------------------------------------
Interfaces in Java (4)
•••• Implementierung von Interfaces
◇ Der Sinn von Interfaces liegt in der Definition von Schnittstellen, die zur Realisierung einer Funktionalität durch Klassen implementiert werden müssen.
◇ Eine Klasse, die ein Interface implementiert, muß sämtliche Methoden des Interfaces (einschliesslich der von Basis- Interfaces geerbten) definieren (d.h. für sie eine Implementierung bereitstellen) oder selbst als abstract deklariert sein. Im letzteren Fall können – müssen aber nicht – die nicht implementierten Methoden des Interfaces als abstrakt deklariert werden Prinzipiell entspricht die Implementierung eines Interfaces damit der Ableitung von einer (rein) abstrakten Klasse.
◇ Eine Klasse kann – gegebenenfalls zusätzlich zur Ableitung von einer Klasse – mehrere Interfaces implementieren. � Realisierung einer Art eingeschränkter Mehrfachableitung in Java.
◇ Syntax : Interface-Implementierung : Die implements-Klausel muss nach einer – gegebenenfalls vorhandenen – extends-Klausel aufgeführt werden.
◇ Beispiel :
◇ Die Implementierung eines Interfaces wird auch an abgeleitete Klassen vererbt. In einem derartigen Fall ist die Angabe einer implements-Klausel bei der abgeleiteten Klasse nicht explizit notwendig, aber zulässig. � Dem Kopf einer Klassendefinition können nicht in jedem Fall die implementierten Interfaces entnommen werden. Beispiel : public interface GraphObj { /* ... */ } public class Punkt implements GraphObj { /* ... */ } public class Quadrat extends Punkt // implements GraphObj { /* ... */ } Die Klasse Quadrat implementiert auch das Interface GraphObj.
◇ Ob die Klasse eines Objekts ein bestimmtes Interface implementiert, kann mit dem instanceof-Operator überprüft werden. Beispiel : Quadrat qd = new Quadrat(); boolean isgo = qd instanceof GraphObj; // � true
Interface-Name implements
,
public class CompCelBody extends CelBody implements Comparable<CompCelBody> { private int orbDist; public CompCelBody(String bName, CelBody orbAround, int dist) { super(bName, orbAround); orbDist = dist; } public int compareTo(CompCelBody o) { if (getOrbits() == o.getOrbits()) return orbDist-o.orbDist; else throw new IllegalArgumentException("unterschiedlicher Orbit"); } // ... }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 475 – 00 – TH – 06 ------------------------------------------------------------------------------------
Interfaces in Java (5)
•••• Interfaces als Objekt-Referenzen
◇ Objekte einer Klasse, die ein Interface implementiert, lassen sich auch als Instanzen des implementierten Inter- faces behandeln. � Explizite oder implizite Typkonvertierung (cast) eines Objekts in den Typ eines implementierten Interfaces.
◇ Man kann Variable eines Interface-Typs definieren und ihnen Referenzen auf Objekte einer implementierenden Klasse zuweisen. Natürlich lassen sich über eine Interface-Variable auch nur die Komponenten eines Objekts ansprechen, die in dem implementierten Interface definiert sind.
◇ Beispiel :
◇ Jede Objekt-Referenz eines Interface-Typs lässt sich allerdings als Referenz auf die Klasse Object verwenden. Damit lassen sich über eine Interface-Variable auch die in der Klasse Object definierten Methoden aufrufen. Dies ist deswegen möglich, da ja das referierte Objekt von irgendeiner Klasse sein muß und jede Klasse von Object abgeleitet ist. Beispiel : // ... GraphObj go = new FPunkt(5,5, Color.BLACK);
String str = go.toString(); // keine Methode von GraphObj, aber von Object // ... •••• Marker Interfaces
◇ Es kann auch sinnvoll sein, ein Interface leer, d.h. ohne jegliche Komponenten, zu definieren.
◇ Ein derartige Interface dient dazu, anzuzeigen, dass eine implementierende Klasse über eine bestimmte Eigenschaft verfügt. Es markiert die Klasse hinsichtlich des Besitzes dieser Eigenschaft � Marker Interface
◇ In der Java-Standardbibliothek sind mehrere derartige Marker Interfaces enthalten. Beispiele :
▻ Cloneable (Package java.lang) Es legt fest, dass Objekte einer implementierenden Klasse mit der clone()-Methode geclont werden können. Die clone()-Methode ist selbst nicht Komponente des Interfaces, sondern der Klasse Object.
▻ Serializable (Package java.io) Es kennzeichnet, dass Objekte einer implementierenden Klasse serialisiert (in einen Byte-Stream umgewandelt) und deserialisiert (aus einem Byte-Stream wiedergewonnen) werden können. Klassen, die zur Realisierung des Serialisierungs-/Deserialisierungs-Mechanismus einer besonderen Behandlung bedürfen, müssen die Methoden writeObject() und readObject() implementieren. Diese Methoden sind aber keine Komponenten des Interfaces Serializable.
public interface GraphObj { void show(); void hide(); // ... } public class FPunkt implements GraphObj { // ... public FPunkt(int x, int y, Color f) { /* ... */ } public void show() { /* ... */ } public void hide() { /* ... */ } // ... public void drawPoint() { /* ... */ } // ... } // ... GraphObj go = new FPunkt(1,1, Color.GREEN); go.show(); go.drawPoint(); // unzulässig ! // ...
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 481 – 00 – TH – 03 -----------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (1)
•••• Überblick
◇ In Java können (ab JDK 1.1) Klassen und Interfaces auch innerhalb anderer Klassen und Interfaces definiert werden. � eingebettete Typen (nested types).
◇ Die Definition eingebetteter Typen ist möglich als
▻ Komponente der umgebenden Klasse bzw des umgebenden Interfaces
▻ lokale Klasse innerhalb eines in der umgebenden Klasse enthaltenen Codeblocks (z.B. in einer Memberfunktion, Konstruktor oder Initialisierungsblock)
◇ Die Möglichkeit, eingebettete Typen zu definieren, ist im wesentlichen in zweierlei Hinsicht zweckmässig :
▻ Strukturierung von Klassen und Interfaces in Gruppen entsprechend ihres logischen Zusammenhangs
▻ Definition von mit spezieller Funktionalität ausgestatteten "Hilfs"- oder "Adaptor"-Klassen an genau der Stelle im Programm, an der sie gebraucht werden. Dadurch lassen sich logisch zusammenhängende Objekte in einfacher und effizienter Weise miteinander verbinden. Hiervon wird insbesondere im Event-Model der GUI-Klassen der JFC (Java Foundation Classes) und in der Java- Beans-Komponenten-Architektur Gebrauch gemacht.
◇ Ein eingebetteter Typ kann als Bestandteil des umschliessenden Typs aufgefaßt werden. Das bedeutet, dass die beiden Typen prinzipiell gegenseitigen Zugriff auch zu ihren jeweiligen private- und protected- Komponenten besitzen (Unterschied zu C++ !).
◇ Ein eingebetteter Typ kann i.a. wieder eingebettete Typen enthalten Grundsätzlich ist eine Einbettung in beliebiger Tiefe möglich. Allerdings vermindert jede weitere Einbettung die Übersichtlichkeit und Klarheit einer Klassendefinition. Eine Einbettung über mehr als zwei Ebenen sollte daher vermieden werden. In den meisten Fällen ist eine Einbettungsebene ausreichend.
◇ Der Compiler erzeugt für jeden eingebetteten Typ eine eigene class-Datei. Deren Haupt-Name (=Typ-Name) wird aus den Typnamen des umschliessenden und des eingebetteten Typs zusammengesetzt (Trennung durch $)
•••• Arten eingebetteter Typen
◇ Es existieren vier verschieden Arten eingebetteter Typen. Sie unterscheiden sich hinsichtlich des Orts und der Art ihrer Definition (Komponente / lokale Klasse, statisch/nicht- statisch, Typname / namenlos)
◇ Eingebettete Top-Level-Klassen und –Interfaces (nested top level classes and interfaces) Sie werden als static-Komponenten einer Klasse oder eines Interfaces definiert. Eingebettete Interfaces sind immer von dieser Art (sie sind implizit static). Auch alle innerhalb eines Interfaces definierte Typen (Klassen und Interfaces) sind immer implizit static (und public) und damit ebenfalls immer von dieser Art.
◇ Innere Klassen (inner classes, member classes) Sie werden als Komponenten einer Klasse, die nicht static sind, definiert. Ihre Definition als Interface-Komponente ist nicht möglich. Auch gibt es keine inneren Interfaces. Ein Objekt einer inneren Klasse ist immer mit einem Objekt der umfassenden Klasse assoziiert.
◇ Lokale Klassen (local classes, local inner classes) Sie werden innerhalb eines Code-Blocks definiert und sind nur innerhalb dieses Blockes verwendbar. Lokale Interfaces sind nicht möglich.
◇ Anonyme Klassen (anonymous classes) Hierbei handelt es sich ebenfalls um Klassen, die innerhalb eines Code-Blocks definiert werden (es sind also auch lokale Klassen). Im Unterschied zu "normalen" lokalen Klassen werden sie aber ohne Namen innerhalb eines new- Ausdrucks definiert. Anonyme Interfaces sind ebenfalls nicht möglich.
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 482 – 00 – TH – 04 ------------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (2) •••• Eingebettete Top-Level-Klassen und –Interfaces
◇ Normalerweise werden Klassen und Interfaces auf der globalen Ebene innerhalb einer jeweils eigenen Quelldatei – gegebenenfalls als Mitglied eines Packages – definiert. Derartige Klassen / Interfaces werden als Top-Level-Klassen / -Interfaces bezeichnet.
◇ Eingebettete Top-Level-Klassen / -Interfaces sind Typen, die innerhalb einer umschliessenden Klasse / Interface als static-Komponente definiert sind. Dabei sind alle innerhalb eines Interfaces definierte Klassen oder Interfaces implizit static (und public). Ebenfalls sind alle innerhalb einer Klasse definierten Interfaces implizit static. Die explizite Angabe des Modifiers static ist in diesen Fällen also überflüssig, aber zulässig.
◇ Diese Typen verhalten sich wie "normale" – nicht eingebettete – Top-Level-Typen, mit dem Unterschied, dass ihr Name und ihre Zugreifbarkeit durch den umschliessenden Typ festgelegt wird. Sie lassen sich ausserhalb ihrer umschliessenden Klasse / Interface prinzipiell wie jeder andere Top-Level-Typ ver wenden, mit den Einschränkungen, dass
▻ ihr Name mit dem Namen des umschliessenden Typs qualifiziert werden muß (� vollqualifizierter Name)
▻ und zu ihnen nur zugegriffen werden kann, wenn auch der umschliessende Typ zugreifbar ist. Unter Berücksichtigung dieser Einschränkungen und der jeweiligen Zugriffsberechtigung kann ein eingebetteter Top- Level-Typ von einer anderen Klasse / Interface abgeleitet sein bzw selbst Basisklasse / Basisinterface für weitere Ab- leitungen sein. Eine eingebettete Top-Level-Klasse kann beliebige Interfaces implementieren und kann instanziiert werden. Sie kann final oder abstract deklariert werden.
◇ Bezüglich der Zugreifbarkeit eingebetteter Typen gelten die gleichen Regeln wie für die Daten- bzw Funktionskom- ponenten einer Klasse /eines Interfaces. Das bedeutet, dass innerhalb einer Klasse definierte eingebettete Typen die Zugriffsberechtigungen private, package, protected oder public besitzen können. Für innerhalb eines Interfaces definierte Typen ist dagegen die Zugriffsberechtigung public implizit festgelegt.
◇ Da eingebettete Top-Level-Typen Komponenten ihrer jeweiligen umschliessenden Klasse sind, besteht zwischen ihnen und dieser Klasse ein besonders privilegiertes Verhältnis bezüglich der gegenseitigen Zugriffsberechtigung : Die eingebetteten Typen dürfen zu allen anderen Komponenten ihrer umschliessenden Klasse – insbesondere auch zu den private deklarierten – zugreifen. Umgekehrt gilt, dass auch die umschliessende Klasse die Zugriffsberechtigung zu allen Komponenten der eingebet- teten Klasse besitzt. Zu den nicht-statischen Komponenten kann natürlich nur über ein Objekt der jeweiligen Klasse zugegriffen werden. Das privilegierte Zugriffsberechtigungsverhältnis wird nicht an abgeleitete Klassen vererbt.
◇ Eingebettete Top-Level-Klassen / -Interfaces dienen zur Strukturierung logisch zusammenhängender Typen.
◇ Beispiel :
public class MyLinkedList { public static interface Linkable // eingebettetes Interface { public Linkable getNext();
public void setNext(Linkable neu);
} private Linkable head; public void insert(Linkable neu) { /* ... */ } public void remove(Linkable elem) { /* ... */ } } public class LinkableInteger implements MyLinkedList.Linkable { private int val; private MyLinkedList.Linkable next; public LinkableInteger(int i) { val = i; next = null; } public MyLinkedList.Linkable getNext() { return next; } public void setNext(MyLinkedList.Linkable neu) { next = neu; } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 483 – 01 – TH – 05 ------------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (3 - 1)
•••• Innere Klassen
◇ Dies sind Klassen, die innerhalb einer anderen Klasse als nicht-statische Komponenten definiert werden.
◇ Eine innere Klasse kann prinzipiell analog zu einer Top-Level-Klasse definiert werden. Allerdings darf sie keine static-Komponenten besitzen Ausnahme : sie darf Konstante (static final, initialisiert mit einem konstanten Ausdruck) enthalten.
◇ Eine innere Klasse kann von einer beliebigen anderen Klasse abgeleitet sein und beliebige Interfaces implementieren. Sie kann Basisklasse für beliebige andere Klassen sein, sofern sie für diese zugreifbar ist. Sie kann final oder abstract deklariert werden.
◇ Ein Objekt einer inneren Klasse muß immer mit genau einem Objekt der umschliessenden Klasse assoziiert sein (Die Umkehrung gilt nicht). Der Compiler ergänzt die Parameterliste jedes Konstruktors einer inneren Klasse um ein verborgenes Argument, dem implizit eine Referenz auf das assoziierte Objekt der umschliessenden Klasse übergeben wird. Diese Referenz wird in einer zusätzlichen – ebenfalls vom Compiler automatisch eingefügten – final-Daten- komponente abgelegt. Über diese Datenkomponente kann das Objekt der inneren Klasse implizit zu allen – auch den private-Kompo- nenten des assoziierten Objekts der umschliessenden Klasse zugreifen.
◇ Beispiel : Klasse BankKonto mit innerer Klasse Buchung (s. nächste Seite)
◇ Die implizit abgelegte Referenz auf das Objekt der umschliessenden Klasse kann auch explizit angegeben werden. Syntax : Das Objekt der inneren Klasse kann damit auch über diese explizite Referenz zu den Komponenten des Objekts der umschliessenden Klasse zugreifen. Beispiel : Zugriff zur Datenkomponente nummer des assoziierten Objekts der umschliessenden Klasse BankKonto aus einem Objekt der inneren Klasse Buchung : BankKonto.this.nummer (s. Beispiel nächste Seite) Eine explizite Referenz ist insbesondere sinnvoll (und dann auch notwendig), wenn
▻ Komponenten der umschliessenden Klasse durch gleichnamige Komponenten der inneren Klasse überdeckt werden. (Eine Methode einer inneren Klasse überdeckt alle überladenen Formen einer gleichnamigen Methode der um- schliessenden Klasse)
▻ zu Komponenten einer umschliessenden Klasse höherer Ebene zugegriffen werden soll.
◇ Aus der umschliessenden Klasse kann ebenfalls zu den privaten Komponenten der inneren Klasse zugegriffen werden – allerdings nur über eine explizite Referenz auf ein Objekt der inneren Klasse. •••• Instanziierung innerer Klassen
◇ Normalerweise werden innere Klassen in Instanz-Memberfunktionen der umschliessenden Klasse instanziiert. In einem derartigen Fall ist die Referenz auf das Objekt der umschliessenden Klasse durch this gegeben.
◇ Soll ein neu zu erzeugendes Objekt der inneren Klasse dagegen mit einem anderen Objekt der umschliessenden Klasse assoziiert werden, so muß dieses bei der Objekterzeugung explizit angegeben werden Hierfür existiert eine Erweiterung der Syntax für den new-Ausdruck : qualified class instance creation expression Syntax : Beispiel : Klasse Buchung sei innere Klasse von BankKonto Eine Methode von BankKonto (z.B. main()) könnte folgenden Code enthalten : BankKonto deinKto = new BankKonto(2481); Buchung buchg = deinKto.new Buchung(null, 0.0f);
Name_der_umschliessenden_Klasse . this
Referenz_auf_umschliessendes_Objekt . new Konstruktoraufruf
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 483 – 02 – TH – 01 -----------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (3 - 2) •••• Demonstrationsbeispiel zu inneren Klassen
// BankKonto.java import java.io.*; public class BankKonto { private long nummer; private float ktoStand; private Buchung letzteBuch; // ---------------------------- innere Klasse ------------------------------- public class Buchung {
private String art;
private float betrag;
Buchung(String act, float betr)
{ art = act;
betrag = betr;
}
public String toString()
{ return nummer + " : " + art + ' ' + betrag; // BankKonto.this.nummer }
} // -------------------------------------------------------------------------- public BankKonto(long num) { nummer = num; ktoStand = 0.0f; letzteBuch = null; } public void einzahlen(float betr) { ktoStand += betr; letzteBuch = new Buchung("Einzahlung", betr); } public boolean abbuchen(float betr) { boolean bRet = true; if (ktoStand >= betr) { ktoStand -= betr; letzteBuch = new Buchung("Abbuchung", betr); } else { letzteBuch = new Buchung("Versuch der Kontoueberziehung", betr); bRet = false; } return bRet; } public void ueberweisen(BankKonto empf, float betr) { if (abbuchen(betr)) { empf.einzahlen(betr); letzteBuch = new Buchung("Ueberweisung ab ", betr); empf.letzteBuch = empf.new Buchung("Ueberweisung auf ",betr); } } // ... }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 483 – 03 – TH – 04 ------------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (3 - 3) •••• Ableitung innerer Klassen
◇ Analog zu Top-Level-Klassen können auch innere Klassen abgeleitet werden. Die abgeleitete Klasse kann sowohl eine Top-Level-Klasse als auch eine innere Klasse sein.
◇ Die einzige besondere Erfordernis ist, dass auch ein Objekt der abgeleiteten Klasse mit einem Objekt der ursprüng- lichen umfassenden Klasse (d.h. der umfassenden Klasse seiner Basisklasse) oder einer davon abgeleiteten Klasse assoziiert sein muß (Basisklassen-Teilobjekt enthält verborgene Komponente auf assoziiertes Objekt !). I.a. ist das kein Problem, da die abgeleitete Klasse meist als innere Klasse einer Klasse, die von der ursprünglichen umschliessenden Klasse abgeleitet ist, definiert wird.
◇ Beispiel : Da hier sowohl Inner als auch die hiervon abgeleitete Klasse ExtInner innere Klassen sind, wird bei der Er- zeugung eines Objekts der Klasse ExtInner (z.B. zur Initialisierung von ref) dieses zweimal an ein Objekt der Klasse ExtOuter gebunden : - Das ExtOuter-Objekt wird dem Konstruktor von ExtInner implizit übergeben. Mit ihm wird die für das Objekt der Klasse ExtInner angelegte verborgene Komponente initialisiert - Zum anderen wird dieses Objekt auch dem – hier implizit aufgerufenen – Konstruktor der Basisklasse Inner (super()) implizit übergeben Dieser setzt die für das Teilobjekt der Klasse Inner angelegte und vom ExtInner-Objekt geerbte verbor- gene Komponente damit auf dasselbe ExtOuter-Objekt.
◇ Wenn die von der inneren Klasse abgeleitete Klasse selbst keine innere Klasse ist, dann muß dem Konstruktor ihrer Basisklasse eine explizite Referenz auf ein assoziierendes Objekt deren umschliessender Klasse übergeben werden. Hierfür existiert wiederum eine spezielle Syntax : Syntax : Beispiel :
Referenz_auf_umschliessendes_Objekt . super Parameterliste ) (
class Outer { class Inner { // ... } // ... } class ExtOuter extends Outer { class ExtInner extends Inner { // ... } // ... Inner ref = new ExtInner(); // ... }
class ExtNotInner extends Outer.Inner { ExtNotInner(Outer ref) { ref.super(); } // ... }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 484 – 01 – TH – 03 ------------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (4- 1)
•••• Lokale Klassen
◇ Dies sind Klassen, die innerhalb eines Codeblocks (Methode, Konstruktor oder Initialisierungsblock) definiert sind.
◇ Sie können von beliebigen anderen Klassen abgeleitet sein und beliebige Interfaces implementieren.
◇ Es handelt sich bei Ihnen nicht um Klassenkomponenten.
◇ Sie sind lokal zu dem Block, in dem sie definiert sind, analog zu lokalen Variablen. Ausserhalb dieses Blocks ist ihre jeweilige Definition nicht zugänglich und damit auch nicht verwendbar.
◇ Instanzen von Ihnen können aber prinzipiell wie Objekte anderer Klassen verwendet werden. Sie existieren nach ihrer Erzeugung, bis sie nicht mehr referiert werden. Referenzen auf sie können als Funktionswerte zurückgegeben und als Parameter an Funktionen übergeben werden. Da ihr Klassenname ausserhalb des definierenden Codeblocks nicht zugänglich ist, werden derartige Objekte i.a. dann als Instanzen eines von ihnen implementierten Interfaces oder einer Basisklasse referiert
◇ Wie innere Klassen dürfen sie keine static-Komponenten besitzen, ausgenommen Daten-Komponenten, die als static und final deklariert sind (Konstante)
◇ Lokale Klassen können nicht mit einem Zugriffs-Spezifizierer (public, protected, private) deklariert werden
•••• Zugriffsmöglichkeiten von lokalen Klassen
◇ Lokale Klassen können zu allen lokalen Variablen und Funktionsparametern, die in ihrem Sichtbarkeitsbereich (scope) liegen und die als final vereinbart sind, zugreifen. Derartige Variablen / Funktionsparameter werden den Konstruktoren einer lokalen Klasse implizit über vom Compiler hinzugefügte verborgene Parameter übergeben. Sie dienen zur Initialisierung von entsprechenden – ebenfalls vom Compiler hinzugefügten – privaten Datenkomponenten der lokalen Klasse. Genaugenommen arbeiten die Objekte einer lokalen Klasse also nicht mit den originalen lokalen Variablen und Funk- tionsparametern sondern mit Kopien derselben. Allerdings werden in den folgenden Fällen keine privaten Datenkomponenten für lokale Variable / Funktionspara- meter angelegt :
▻ lokale Variable / Funktionsparameter, die in der lokalen Klasse nicht verwendet werden
▻ lokale final-Variable eines einfachen Datentyps, die gleich bei ihrer Definition initialisiert werden (= lokale Konstante). Ihr jeweiliger Wert wird direkt als Konstante eingesetzt
◇ Objekte einer lokalen Klasse, die innerhalb einer nicht-statischen Memberfunktion oder in einem Objekt-Initialisie- rungsblock definiert ist, müssen – wie Objekte innerer Klassen – immer an ein Objekt der umschliessenden Klasse gebunden sein. Damit haben sie direkten Zugriff zu allen Komponenten dieses Objekts. Die Implementierung dieser Bindung ist analog zu inneren Klassen realisiert (Übergabe einer Referenz auf das assoziierte Objekt der umschliessenden Klasse über einen verborgenen Konstruktorparameter und Speicherung derselben in einer hinzugefügten privaten Datenkomponente). Auch die explizite Referierung des assoziierten Objekts ist – mit derselben Syntax – wie bei inneren Klassen möglich (Erweiterte Form der this-Referenz).
◇ Objekte einer lokale Klasse, die in einer statischen Memberfunktion oder in einem Klassen-Initialisierungsblock definiert ist, besitzen kein assoziiertes Objekt der umschliessenden Klasse. Sie können direkt nur zu statischen Komponenten der umschliessenden Klasse zugreifen. Zum Zugriff zu den nicht-statischen Klassenkomponenten benötigten sie eine explizite Objekt-Referenz.
•••• Typische Anwendung von lokalen Klassen
◇ Event-Listener-Klassen für GUI-Komponenten der JFC werden häufig als lokale Klassen definiert (Adapter-Klassen). Allerdings ist für diese auch die Definition als innere Klassen oder als anonyme Klassen üblich.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 484 – 02 – TH – 02 -----------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (4- 2) •••• Demonstrationsprogramm zu lokalen Klassen
Programmausgabe :
// ArrayWalker.java // Implementierung einer Klasse, die eine – hier statische – Memberfunktion // makeEnum() zur Erzeugung eines Enumeration-Objekts für Arrays bereitstellt. // Die Klasse ArrayEnum des erzeugten Enumeration-Objekts ist als lokale Klasse // der Erzeugungs-Funktion implementiert. // Sie implementiert das Bibliotheks-Interface Enumeration import java.util.Enumeration; public class ArrayWalker { public static Enumeration makeEnum(final Object[] objs) {
final int startpos; startpos = 0; // nur zu Demo-Zwecken so umstaendlich // ------------------------ lokale Klasse ------------------------------- class ArrayEnum implements Enumeration
{
private int pos = startpos; // nur zu Demo-Zwecken so umstaendlich
public boolean hasMoreElements()
{
return pos < objs.length;
}
public Object nextElement()
{
return objs[pos++];
}
}
// ---------------------------------------------------------------------- return new ArrayEnum(); } // Demonstration der Anwendung public static void main(String[] args) { final int anz = 10; Integer[] ia = new Integer[anz]; for (int i=0; i<anz; i++) ia[i]=new Integer(i); for (Enumeration e = makeEnum(ia); e.hasMoreElements(); ) System.out.print(e.nextElement() + " "); System.out.println(); } }
0 1 2 3 4 5 6 7 8 9
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 485 – 01 – TH – 02 -----------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (5- 1)
•••• Anonyme Klassen
◇ Anonyme Klassen sind im wesentlichen lokale Klassen ohne Namen. Sie verfügen über alle Eigenschaften von lokalen Klassen, die nicht vom Besitz eines Klassennamens abhängen.
◇ Sie müssen immer von einer anderen Klasse abgeleitet sein oder genau ein Interface implementieren.
◇ Sie werden gleichzeitig mit ihrer Instanziierung in einem new-Ausdruck definiert. Von ihnen lässt sich also immer nur ein Objekt erzeugen.
◇ Zur Realisierung anonymer Klassen existiert eine entsprechende Erweiterung der Syntax für den new-Ausdruck : Der new-Ausdruck wird nicht – wie bei Klassen mit Namen – mit einem Semikolon abgeschlossen, sondern durch einen Klassen-Rumpf ergänzt. Der Klassen-Rumpf bildet die Definition der anonymen Klasse. Er enthält die Definition ihrer Komponenten und Initialisierungsblöcke. Der im new-Ausdruck anzugebende Klassen-/bzw Interface-Name
▻ ist der Name der Klasse, von dem die anonyme Klasse abgeleitet ist
▻ bzw der Name des Interfaces, das sie implementiert. Eine nicht-leere Parameterliste kann nur im Fall der Ableitung von einer anderen Klasse angegeben werden. Die Parameter werden dem implizit aufgerufenen Konstruktor der Basisklasse übergeben. Im Fall der Implementierung eines Interfaces muss die Parameterliste leer sein. Die explizite Angabe einer extends- oder implements-Klausel ist nicht möglich.
◇ Beispiel :
◇ Für anonyme Klassen kann kein expliziter Konstruktor definiert werden (kein Klassenname !). Stattdessen erzeugt der Compiler implizit einen anonymen Konstruktor, der den Basisklassen-Konstruktor aufruft. Falls Komponenten eines Objekts einer anonymen Klasse bei der Erzeugung explizit initialisiert werden sollen, muß dies durch Initialisierungsausdrücke bzw einen Intialisierungsblock erfolgen.
◇ Da anonyme Klassen keinen Namen besitzen, können sie nicht als Basisklasse verwendet werden � anonyme Klassen sind implizit final.
Parameterliste ( new Klassen-/Interface-Name ) {
Klassen-Rumpf }
// DirLister.java import java.io.*; public class DirLister { public static void main(String[] args) { File dir = new File(args[0]); // Achtung : hier keine Überprüfung final String endung = args[1]; // auf richtiges Aufrufformat String[] flist = dir.list(new FilenameFilter() { public boolean accept(File d, String s)
{ return s.endsWith(endung);
}
}); for (int i=0; i<flist.length; i++) System.out.println(flist[i]); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 485 – 02 – TH – 01 -----------------------------------------------------------------------------------
Eingebettete Klassen und Interfaces in Java (5- 2) •••• Verwendung anonymer Klassen
◇ Anonyme Klassen werden häufig konkurierend zu – benannten – lokalen Klassen eingesetzt. Sie dienen im wesentlichen auch zur Definition von Adapter-Klassen, wie z.B. Event-Listener-Klassen für GUI-Komponenten.
◇ Die Verwendung einer anonymen Klasse statt einer lokalen Klasse kann insbesondere sinnvoll sein, wenn
▻ die Definition der Klasse sehr kurz ist (nur wenige Quellcode-Zeilen umfasst),
▻ nur ein Objekt der Klasse benötigt wird
▻ die Klasse direkt dort, wo sie definiert wird, auch verwendet werden soll,
▻ ein Klassenname nicht explizit benötigt wird und die Vergabe eines Klassennamens den Code nicht verständ- licher macht.
•••• class-Dateiname einer anonymen Klasse
◇ Der Haupt-Name der vom Compiler erzeugten class-Datei für eine anonyme Klasse besteht aus dem Namen der umschliessenden Klasse gefolgt vom Zeichen $ und einer laufenden Nummer.
•••• Demonstrationsprogramm zu anonymen Klassen Realisierung der Klasse ArrayEnum (s. Demonstrationsprogramm zu lokalen Klassen) als anonyme Klasse
// ArrayWalker2.java import java.util.Enumeration; public class ArrayWalker2 { public static Enumeration makeEnum(final Object[] objs) { final int startpos; startpos=0; return new Enumeration() { // Definition der anonymen Klasse private int pos = startpos;
public boolean hasMoreElements()
{
return pos < objs.length;
}
public Object nextElement()
{
return objs[pos++];
}
}; } public static void main(String[] args) { final int anz = 10; Integer[] ia = new Integer[anz]; for (int i=0; i<anz; i++) ia[i]=new Integer(i); for (Enumeration e = makeEnum(ia); e.hasMoreElements(); ) System.out.print(e.nextElement() + " "); System.out.println(); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 491 – 00 – TH – 03 ------------------------------------------------------------------------------------
Generische Klassen, Interfaces und Funktionen (Generics) in Java (1)
•••• Allgemeines
◇ Mit dem JDK 5.0 wurde in Java die Möglichkeit der generischen Programmierung mittels Typ-Parameterieisrung eingeführt (Konzept der Generics)
◇ Typ-Parameterisierung lässt sich anwenden bei :
▻ Klassen � generische Klassen
▻ Interfaces � generische Interfaces
▻ Memberfunktionen � generische Methoden
▻ Konstruktoren � generische Konstruktoren
◇ Typ-Parameterisierung bedeutet, dass bei der Definition einer Klasse (bzw Interface, bzw Methode bzw Konstruktor) durch eine Typ-Param-Deklaration formale Typ-Parameter (Typ-Variablen) definiert werden. Dabei kann eine Typ-Variable durch eine Typ-Begrenzung (Type Bound) ergänzt werden Zur Anwendung der Klasse (bzw Interface, Methode, Konstruktor) müssen dieTyp-Variablen durch konkrete aktuelle Typ-Parameter (Typ-Argumente) ersetzt werden. Dadurch lässt sich der gleiche – nur einmal vorhandene – Code für unterschiedliche Typen verwenden.
•••• Typ-Param-Deklaration
◇ Sie ist anzugeben bei
▻ der Klassen- und Interface-Definition : unmittelbar nach dem Klassen- bzw Interface-Namen
▻ der Methoden-Definition : unmittelbar vor dem Rückgabetyp
▻ der Konstruktor-Definition : unmittelbar vor dem Konstruktor(==Klassen)-Namen
◇ Syntax der Typ-Param-Deklaration :
Typ-Parameter : Typ-Begrenzung : (Type Bound)
◇ Durch Angabe einer Typ-Begrenzung werden die Typen der möglichen aktuellen Typ-Parameter (Typ-Argumente) eingeschränkt. Ein Typ-Argument muss zu der jeweiligen Typ-Begrenzung kompatibel sein, d.h. gleich dem angegebenen Klassen- Typ oder von ihm abgeleitet sein und/oder die angegebenen Interface-Typen implementieren. Das Schlüsselwort extends steht hier sowohl für die Ableitung als auch für die Implementierung.
◇ Beispiele : public interface Map<K, V> { ... } public class EnumMap<K extends Enum<K>, V> extends ... implements ... { ... } public static <T extends Number & Serializable & Comparable<T>> T getMaxElement(Collection<T> coll) { ... }
Typ-Parameter <
,
>
formaler Typ-Name
Typ-Begrenzung
extends
Klassen-Typ
Interface-Typ
& Interface-Typ
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 492 – 00 – TH – 03 ------------------------------------------------------------------------------------
Generische Klassen, Interfaces und Funktionen (Generics) in Java (2) •••• Anmerkungen zu generischen Klassen und Interfaces
◇ Die bei der Definition einer generischen Klasse bzw Interfaces deklarierten formalen Typ-Parameter (Typ-Variable) können in der gesamten Klassendefinition verwendet werden, einschliesslich der Typ-Param-Deklaration selbst. (z.B. in der eigenen Typ-Begrenzung oder den Typ-Begrenzugen anderer Typ-Variabler) Innerhalb der Klassendefinition können sie als Typ-Angabe für Datenkomponenten, Parameter- und Rückgabetyp von Memberfunktionen sowie in eingebetteten Typen auftreten. Ausnahmen :
▻ Typ-Parameter von generischen Klassen dürfen nicht verwendet werden : - für statische Datenkomponenten (einschliesslich statischer Datenkomponenten eingebetteter Typen) - in statischen Funktionskomponenten (einschliesslich statischer Funktionskomponenten eingebetteter Typen) - in statischen Initialisierungsblöcken (einschliesslich statischer Initialisierungsblöcke eingebetteter Typen)
▻ Typ-Parameter von generischen Interfaces dürfen nicht verwendet werden : - für Datenkomponenten (sind immer implizit static und final) - in eingebetteten Typen
◇ Durch Anwendung aktueller Typ-Parameter (Typ-Argumente) wird aus einer generischen Klasse oder Interface ein konkreter Typ erzeugt � parameterisierter Typ
◇ Alle aus einer generischen Klasse erzeugbaren parameterisierten Typen teilen sich dieselbe Klasse � der folgende Ausdruck liefert true : new Vector<Integer>().getClass() == new Vector<String>().getClass();
◇ Eine generische Klasse sowie ein aus einer generischen Klasse erzeugter parameterisierter Typ kann Basisklasse für andere generische und nicht-generische Klassen sein. Folgende Klassendefinitionen sind somit prinzipiell zulässig : public class GenVector<T> extends Vector<T> { ... } public class Menge<T> extends Vector<String> { ... } public class SpecVector extends Vector<T> { ... } public class MyIntList extends LinkedList<Integer> { ... } Analog können generische Interfaces und aus diesen gewonnene parameterisierten Typen von generischen und nicht-generischen Klassen implementiert werden
◇ Eine generische Klasse darf weder direkt noch indirekt von Throwable abgeleitet sein. � Exception-Klassen können nicht generisch sein. •••• Raw Types
◇ Generische Klassen und Interfaces können auch ganz ohne Typ-Argumente verwendet werden. Der dadurch erhaltene Typ wird als Raw Type bezeichnet.
◇ Innerhalb eines Raw Types sind alle Auftritte einer Typ-Variablen (formaler Typ-Parameter) durch den Typ Object bzw – falls vorhanden – den ersten Typ einer Typ-Begrenzung ersetzt. Alle eventuell enthaltenen Vorkommen von generischen Klassen/Interfaces sowie parameterisierten Typen werden durch ihre zugehörigen Raw Types ersetzt. Der zu dieser Ersetzung führende Mechanismus wird Type Erasure genannt.
◇ Raw Types ermöglichen die Kompatibilität zu nicht-generischem Java-Code Mit ihrer Anwendung geht allerdings auch die durch die Typ-Parameterisierung erreichte Typ-Sicherheit (Überprüfung durch den Compiler !) verloren. Der Programmierer ist wieder selbst für richtige Type Casts verantwortlich Raw Types sollten daher möglichst nur dort statt parameterisierter Typen verwendet werden, wo es aus Gründen der Kompatibilität zu altem (nicht-generischem ) Code notwendig ist.
public interface Iterator<E> { // ... E next(); }
public interface Iterator { // ... Object next(); }
mittels Type Erasure wird hieraus :
Beispiel :
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 493 – 00 – TH – 02 -----------------------------------------------------------------------------------
Generische Klassen, Interfaces und Funktionen (Generics) in Java (3) •••• Anmerkungen zu generischen Methoden und Konstruktoren
◇ Die Definition/Deklaration generischer Methoden und Konstruktoren ist unabhängig von einer generischen Eigen- schaft ihrer jeweiligen Klasse/Interface. � Generische Methoden/Konstruktoren lassen sich sowohl für generische als auch normale nicht-generische Klassen/Interfaces vereinbaren.
◇ Auch statische Methoden können generisch sein.
◇ Die bei der Definition einer generischen Methode bzw Konstruktors deklarierten Typ-Variablen (formale Typ- Parameter) können in der gesamten Funktionsdefinition verwendet werden, einschliesslich der Typ-Param- Deklaration selbst (z.B. in der eigenen Typ-Begrenzung oder den Typ-Begrenzugen anderer Typ-Variabler), Innerhalb der Funktionsdefinition können sie als Typ-Angabe für lokale Variable, sowie Parameter- und Rück- gabetyp der Funktion auftreten.
◇ Beispiele :
◇ Aufruf generischer Methoden :
▻ Im Normalfall kann eine generische Funktion ohne explizite Angabe von aktuellen Typ-Parametern (Typ-Argu- mente) aufgerufen werden. Fast immer kann der Compiler die aktuellen Typ-Parameter mittels der sogenannten Type Inference implizit aus dem Funktionsaufruf und seinem Kontext ermitteln.
▻ Falls die aktuellen Typ-Parameter explizit angegeben werden, was natürlich prinzipiell immer möglich ist, müssen sie in spitzen Klammern eingeschlossen unmittelbar vor dem Methoden-/Konstruktor-Namen angegeben werden. Zusätzlich muss das Zielobjekt des Aufrufs (gegebenenfalls für das aktuelle Objekt this) bzw die Klasse (bei statischen Methoden) angegeben werden.
▻ Beispiele :
public class GenericsDemo { public static <T extends Number & Serializable & Comparable<T>> T getMaxElement(Collection<T> coll) { T mv = Collections.max(coll); return mv; } public <T> void fromArrayToCollection(T[] ar, Collection<T> coll) { for (T elem : ar) coll.add(elem); } // ... }
public class GenericsDemo { // ... void main(String[] args) { ArrayList<Integer> ali = new ArrayList<Integer>(); // ... System.out.println(getMaxElement(ali)); System.out.println(GenericsDemo.<Integer>getMaxElement(ali)); Double[] da = {2.5, 3.5, 4.5, 0.5, 1.5}; Vector<Double> dv = new Vector<Double>(); GenericsDemo gendemo = new GenericsDemo(); gendemo./*<Double>*/fromArrayToCollection(da, dv); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 494 – 00 – TH – 02 ------------------------------------------------------------------------------------
Generische Klassen, Interfaces und Funktionen (Generics) in Java (4) •••• Implementierung von Generics
◇ Generics werden in Java allein vom Compiler bearbeitet. Im erzeugten Bytecode (.class-Datei) ist jeglicher Auftritt von Generics entfernt : Er besteht nur aus nicht-gene- rischem Code. � Zur Laufzeit steht keinerlei Information über gegebenenfalls im Quellcode enthaltene generische Eigenschaften (den Typ-Parametern) von Klassen/Interfaces/Methoden/Konstruktoren zur Verfügung. Typ-Variable existieren nicht zur Laufzeit. Die JVM kennt keine Generics.
◇ Bei der Übersetzung von generischem Quellcode entfernt der Compiler die Generics-Informationen mittels Type
Erasure. Er erzeugt also den Byte-Code für Raw Types und "Raw Functions". Allerdings legt er die Generics-Informationen (Informationen über Typ-Parameter !) in sogenannten "Signatur- attributen" ab und bettet diese in dem erzeugten Byte-Code ein. Signaturattribute sind aber kein Bestandteil des Byte- Codes und werden von der JVM (sowie älteren Compilern) ignoriert. Java-Compiler ab dem JDK 5.0 werten sie jedoch bei der Verwendung der Klassen/Interfaces/Methoden/Konstruktoren durch anderen Code aus. Dadurch sind sie in der Lage, auf die Verwendung richtiger Typen zu prüfen und die gegebenenfalls benötigten Type Casts zu erzeugen.
◇ Die Tatsache, dass der Compiler für generische Klassen/Interfaces deren jeweiligen Raw Type erzeugt, erklärt auch, warum für alle erzeugbaren parameterisierten Typen immer nur eine Klasse in der JVM existiert. Analoges gilt für generische Methoden/Konstruktoren. Unabhängig von den bei ihrem Aufruf verwendeten aktuellen Typ-Parametern ist jeweils nur eine einzige Version des Methoden-/Konstruktor-Codes in der JVM enthalten. •••• Grenzen in der Anwendung von Generics
◇ Die Art der Implementierung von Generics (Reduzierung auf Raw Types und "Raw Functions" durch Type Erasure) bedingt, dass mit Typ-Variablen nicht in jeder Hinsicht genauso wie mit konkreten Datentypen umgegangen werden kann.
◇ Typ-Argumente müssen immer Referenztypen sein. Statt einfacher Datentypen müssen daher ihre Wrapperklassen als Typ-Argumente eingesetzt werden. Im übrigen ermöglicht Autoboxing, dass einfache Datentypen wie Referenztypen (Wrapper-Klassen) verwendet werden können.
◇ Typ-Variable dürfen nicht für/in statische Klassen- bzw Interface-Komponenten verwendet werden (s. oben)
◇ Der instanceof-Operator darf nicht verwendet werden für - Typ-Variable - Parameterisierte Typen Beispiele : Integer i = new Integer(25);
if (i instanceof T) // unzulässig (T sei Typ-Variable einer generischen Klasse) // ... ArrayList<Punkt> ali = new ArrayList<Punkt>();
if (ali instanceof ArrayList<Punkt) // unzulässig // ...
◇ Es dürfen keine Konstruktoren von Typ-Variablen aufgerufen werden. Beispiel : class Nogood<T> { private T val;
public Nogood() { val = new T(); } // unzulässig }
◇ Es dürfen keine Arrays von Typ-Variablen erzeugt werden Beispiel : class Behaelter<T>
{ private T[] arr = new T[512]; // unzulässig // ... }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 500 – 00 – TH – 02 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 5
5. Graphische Benutzeroberflächen 5.1. Grundprinzip 5.2. Java Foundation Classes – Überblick 5.3. Basisklassen der JFC-Hierarchie 5.4. Erstellung einer GUI-Anwendung 5.5. Beeinflussung des Erscheinungsbildes 5.6. Ausgewählte Swing-Komponenten-Klassen 5.7. Ereignisverarbeitung
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 511 – 00 – TH – 02 -----------------------------------------------------------------------------------
Grundprinzip graphischer Benutzeroberflächen •••• Aufbau graphischer Benutzeroberflächen
◇ Eine graphische Benutzeroberfläche (Graphical User Interface, GUI) ist typischerweise aus hierarchisch strukturier- ten Komponenten aufgebaut.
◇ Die einzelnen GUI-Komponenten – auch controls oder widgets ( = window gadgets) genannt – erfüllen jeweils spezielle Aufgaben. Die meisten von ihnen ermöglichen es dem Benutzer, durch Eingaben mittels Maus, Tastatur oder einem anderen Eingabegerät mit Ihnen und damit mit dem Programm zu interagieren.
◇ Die hierarchische Struktur einer graphischen Benutzeroberfläche ergibt sich dadurch, dass einige GUI-Komponenten, Container genannt, andere Komponenten enthalten können. An der "Spitze" jeder graphischen Benutzeroberfläche steht ein sogenannter Top-Level-Container. Die in ihm enthal- tenen Komponenten können "elementare" Komponenten oder wiederum Container sein, welche dann weitere Kom- ponenten enthalten können, usw. Eine an einen Container gerichtete Aufgabe (z.B. paint(), "zeichne Dich") führt dieser für sich – soweit zutreffend – aus und delegiert dann die weitere Ausführung an alle in ihm enthaltenen Komponenten. Eine derartige Struktur führt programmtechnisch zu einer Implementierung des Entwurfsmusters Composite.
◇ Beispiele für elementare GUI-Komponenten : ▪ Beschriftung (Label) ▪ Textfeld (Text Field) ▪ Schaltfläche (Button) ▪ Auswahlfeld (Check Box) ▪ Auswahlliste (List, Combo Box) ▪ Menue (Menu)
◇ Beispiele für GUI-Container ▪ Fenster mit Rahmen (Frame) ▪ Dialogbox (Dialog Box) ▪ Menueleiste (Menu Bar) ▪ Werkzeugleiste (Tool Bar) ▪ Gruppierungsfeld (Panel)
◇ Beispiel : Rahmenfenster (Frame) mit Schaltfläche (Button) und Beschriftung (Label)
•••• Interaktion mit dem Benutzer
◇ Die Interaktion mit dem Benutzer erfolgt ereignisgesteuert. Jede auf eine GUI-Komponente fallende Benutzereingabe (Mausklick, Mausbewegung, Tastatureingabe, Auswahl aus einem Menu usw) wird als Ereignis bezeichnet.
◇ Für jede Komponente kann festgelegt werden, auf welches Ereignis wie reagiert werden soll.
◇ Beim Eintritt eines Ereignisses wird die für die betreffende Komponente registrierte Reaktion ausgeführt.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 521 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java Foundation Classes – Überblick (1) •••• Bestandteile der Java Foundation Classes (JFC)
◇ Mit den JFC stellt Java eine breites Spektrum von Bibliotheks-Klassen zur Realisierung graphischer Funktionalität und zum Aufbau von GUIs zur Verfügung.
◇ Die für die Anwendung in GUIs wichtigsten Klassen lassen sich im wesentlichen in die folgenden Gruppen einteilen :
▻ Klassen für elementare GUI-Komponenten
▻ Klassen für GUI-Container
▻ Klassen zur Gestaltung der GUI-Komponenten (Layout-Manager, Farben und Fonts)
▻ Klassen und Interfaces zur Ereignisverarbeitung (Listener, Adapter und Events)
◇ Die JFC umfassen im wesentlichen zwei – sich teilweise ersetzende und teilweise ergänzende – Frameworks :
▻ Abstract Windows Toolkit (AWT) � Package java.awt mit mehreren Unterpaketen
▻ Die Swing-Klassen � Package javax.swing mit mehreren Unterpaketen
◇ Zusätzlich gehören zu den JFC :
▻ Java 2D API (Klassen zur Realisierung fortgeschrittener 2D-Graphik, Bild- und Textbearbeitung sowie Drucken)
▻ Accessibility API (Klassen zur Realisierung von Interfaces für Behinderte)
▻ Klassen zur Unterstützung international einsetzbarer GUI-Applikationen, die sich leicht an die jeweilige Landes- sprache und nationalen Konventionen anpassen. Hierzu gehört u.a. das Input Method Framework API. •••• Abstract Windows Toolkit (AWT)
◇ Ursprüngliches GUI-Paket in Java. Seit dem JDK 1.0 enthalten Im JDK 1.1. wesentlich überarbeitet, insbesondere bezüglich der Ereignis-Bearbeitung
◇ Bildet auch die Grundlage für das spätere Swing-Paket.
◇ Die Implementierung der AWT-Klassen für die GUI-Komponenten verwendet die durch die Graphik-und Window- Funktionalität des jeweiligen Betriebssystems zur Verfügung gestellten Komponenten ("heavyweight" components). Das bedeutet, - dass nur solche Funktionalitäten implementiert werden konnten, die auf allen wichtigen Plattformen, die Java unterstützten, existierten ("kleinster gemeinsamer Nenner") - dass das Aussehen und die Bedienbarkeit ("Look and Feel", LaF) einer graphischen Benutzeroberfläche jeweils systemspezifisch ist. Die einzelnen GUI-Komponenten werden in der durch das jeweilige Betriebssystems vorge- gebenen Art und Weise dargestellt. •••• Die Swing -Klassen
◇ Framework zur Erstellung von GUI-Anwendungen mit erweiterter Funktionalität. Beim JDK 1.1 als Add-On verfügbar, seit dem JDK 1.2 fester Bestandteil der Java 2 Platform.
◇ Die Swing-Klassen bauen auf dem AWT auf, nutzen vieler seiner Grundfunktionalitäten, u.a. das Model und die Klassen für die Ereignisbearbeitung, sowie die Klassen zur Gestaltung der GUI-Komponenten.
◇ Die Implementierung der Klassen für die GUI-Komponenten – ausser den Top-Level-Containern – greift nicht mehr auf die Komponentendarstellung des Betriebssystems zurück. Sie ist vielmehr – unter Verwendung graphischer Primitiv- Operationen ("lightweight components") vollkommen in Java realisiert. Das bedeutet, das das "Look and Feel" einer mit Swing-Komponenten realisierten GUI unabhängig vom jeweiligen Betriebssystem und damit für alle Systeme gleich ist.
◇ Andererseits kann der Programmierer und gegebenenfalls auch der Programmbenutzer das LaF einer GUI-Anwendung selbst festlegen (Pluggable Look and Feel), wobei zwischen einigen Standard-LaFs ausgewählt werden aber auch ein eigenes LaF gestaltet werden kann. Es ist sogar möglich das LaF dynamisch während des Programmlaufs zu verän- dern. Defaultmäßig ist für alle GUI-Komponenten ein Java Look and Feel (Name "Metal") eingestellt.
◇ AWT- und Swing-Klassen für GUI-Komponenten dürfen nicht miteinander gemischt verwendet werden.
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 522 – 00 – TH – 05 ------------------------------------------------------------------------------------
Java Foundation Classes – Überblick (2) •••• Hierarchie der JFC-Klassen für GUI-Komponenten (unvollständig)
MenuComponent
MenuItem
MenuBar
Menu
CheckBoxMenuItem
PopupMenu
AWT Swing Component
Container
Label
Button
Checkbox
… weitere AWT- Komponenten
Panel
Window
ScrollPane
JComponent
Applet
JApplet
Dialog
Frame
JWindow
JDialog
JFrame
FileDialog
JPanel
JComboBox
JMenuBar
JList
Box
JTable
JScrollPane
JPopupMenu
JToolBar
. . .
. . .
. . .
AbstractButton
JTextComponent
JButton
JToggleButton
JCheckBox
JRadioButton
JMenuItem
JTextArea
JTextField
JEditorPane
JMenu
JCheckBoxMenuItem
JPasswordField
… weitere Swing- Komponenten
JTextPane
JRadioButtonMenuItem
. . .
JLabel
Box.Filler
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 523 – 00 – TH – 03 ------------------------------------------------------------------------------------
Java Foundation Classes – Überblick (3) •••• Top-Level-Container
•••• Elementare Komponenten (Auswahl)
•••• "Innere" Container (Auswahl)
AWT Swing Fenster mit Rahmen und Titelleiste Frame JFrame Fenster ohne Rahmen und Titelleiste Window JWindow Dialog-Box Dialog JDialog Applet Applet JApplet
AWT Swing Beschriftung Label JLabel Zeichenfläche Canvas Schaltknopf Button JButton Umschaltknopf (Schaltknopf mit zwei Zuständen) JToggleButton Auswahlfeld Checkbox JCheckBox Gruppe alternativer Auswahlfelder Checkbox JRadioButton (nur ein Feld kann ausgewählt werden) in Verbindung mit in Verbindung mit CheckboxGroup ButtonGroup Auswahlliste List JList aufklappbare Auswahlliste Choice JComboBox einzeiliges Textfeld (editierbar) TextField JTextField mehrzeiliges Textfeld (editierbar) TextArea JTextArea Bildlaufleiste Scrollbar JScrollBar Bildlauffläche (horizontale u. vertikale Bildlaufleiste) ScrollPane JScrollPane Tabelle JTable Menüeintrag MenuItem JMenuItem
AWT Swing Gruppierungsfeld Panel JPanel Gruppierungbox (festliegender Layout-Manager) Box Menüleiste MenuBar JMenuBar Menu Menu JMenu Werkzeugleiste JToolBar
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 524 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java Foundation Classes – Überblick (4) •••• Einige Swing-Komponenten (Java Look and Feel) (Klasse SwingCompDemo)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 531 – 00 – TH – 04 ------------------------------------------------------------------------------------
Basisklassen der JFC-Hierachie (1) •••• Die abstrakte Klasse Component
◇ Diese – im Package java.awt enthaltene – Klasse steht an der Spitze der Hierarchie der GUI-Komponenten- Klassen. Sie definiert grundlegende Methoden, die in fast allen AWT- und Swing-Komponenten-Klassen zur Verfügung stehen. Lediglich die AWT-Klassen für Menü-Komponenten befinden sich in einer hiervon unabhängigen Klassen-Hierarchie.
◇ Einige wesentliche Methoden : (die Methoden zum Registrieren von Listener-Objekten für die Event-Behandlung sind nicht mit aufgeführt )
public void setBackground(Color c) Setzen der Hintergrund-Farbe auf c
public void setForeground(Color c) Setzen der Vordergrund-Farbe auf c
public void setFont(Font f) Setzen der in der Komponente verwendeten Schriftart
public void setSize(int w, int h) Setzen der Breite (auf w) und Höhe (auf h) der Komponente (Angabe in Pixel)
public void setLocation(int x, int y) Setzen der Position der Komponente (linke obere Ecke auf (x,y), Angabe in Pixel)
public void setVisible(boolean b) Anzeigen / Verbergen der Komponente (b==true : Komponente sichtbar, sonst unsichtbar)
public void setEnabled(boolean b) Aktivierung / Deaktivierung der Reaktion der Komponente auf Benutzereingaben (b==true : Komponente kann auf Benutzereingaben reagieren (Events erzeugen)) Defaultmässig sind alle Komponenten aktiviert
public Color getBackground() Rückgabe der Hintergrund-Farbe
public Color getForeground() Rückgabe der Vordergrund-Farbe
public Font getFont() Rückgabe der verwendeten Schriftart
public int getWidth() Rückgabe der aktuellen Breite der Komponente (in Pixel)
public int getHeight() Rückgabe der aktuellen Höhe der Komponente (in Pixel)
public boolean isVisable() Rückgabe des Sichtbarkeits-Status der Komponente true, wenn Komponente sichtbar, false, wenn nicht
public boolean isEnabled() Rückgabe des Aktivierungs-Status der Komponente true, wenn Komponente aktiviert, false, wenn nicht
public void paint(Graphics g) Zeichnen der Komponente unter Verwendung des Graphik- Context-Objekts g. Wird vom System aufgerufen (Callback), z.B. wenn die Kom- ponente erstmals sichtbar gemacht wird oder eine Zustands- (z.B. Größen-) änderung erfolgt ist
public void repaint() Aufforderung an das System, die Komponente neu zu zeichnen (mittels paint()) Kann vom Anwender-Code aufgerufen werden, wenn sich der Zustand des GUI-Objekts geändert hat.
public void validate() Sicherstellung, dass die Komponente ein gültiges Layout hat (Diese Methode ist insbesondere für Container vorgesehen)
public void requestFocusInWindow() Anforderung des Focus (wenn Top-Level-Cont. Focus besitzt )
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 532 – 00 – TH – 03 ------------------------------------------------------------------------------------
Basisklassen der JFC-Hierachie (2)
•••• Die Klasse Container
◇ Diese – im Package java.awt definierte – Klasse ist die Basisklasse aller GUI-Container-Klassen. Auch die Klassen für einfache Swing-Komponenten sind – indirekt – von dieser Klasse abgeleitet. Sie ist selbst von der Klasse Component abgeleitet.
◇ Sie stellt – über die von Component geerbten und teilweise überschriebenen Methoden hinaus – insbesondere Methoden zur Verfügung, die das Verwalten (z.B. Einfügen, Entfernen) von GUI-Komponenten ermöglichen.
◇ Die in einem GUI-Container-Objekt enthaltenen GUI-Komponenten werden in einer Liste verwaltet, wobei die Reihen- folge der Listenelemente standardmässig durch die Reihenfolge ihres Einfügens festgelegt ist. Diese Reihenfolge bestimmt auch die Anordnungs-Reihenfolge der Komponenten entsprechend des jeweils festgeleg- ten Layout-Managers. Es ist aber auch möglich, die Reihenfolge der Komponenten (Position bezüglich des gewählten Layouts) durch einen entsprechenden Parameter ("Index") der Einfüge-Methode explizit zu beeinflussen.
◇ Wenn in einen Container eine Komponente neu eingefügt oder entfernt wird, nachdem der Container bereits sichtbar ist, muß die von Component geerbte – aber überschriebene – Methode validate() aufgerufen werden. Dadurch wird der Layout-Manager des Containers veranlasst, das Layout entsprechend anzupassen.
◇ Die von Component geerbte Methode paint() ist so überschrieben, dass für alle im Container enthaltenen Komponenten deren paint()-Methode aufgerufen wird.
◇ Die wichtigsten Methoden zur Komponentenverwaltung sind : (die Methoden zum Registrieren von Listener-Objekten für die Event-Behandlung sind nicht mit aufgeführt )
◇ Ein Container besitzt Randbereiche (insets), die nicht für die Aufnahme von Komponenten zur Verfügung stehen (z.B. die Titelleiste). Die Randbereiche werden in einem Objekt der Klasse Insets (Package java.awt) zusammengefasst. Die 4 Randbereiche (Angabe in Pixel) sind zugänglich über public-int-Datenkomponenten : top, left, bottom, right.
Zur Ermittlung des Insets-Objekt eines Containers dient die Memberfunktion :
public Insets getInsets() Ermittlung der Randbereiche des Containers
public Component add(Component comp) Einfügen der Komponente comp am Ende des Containers
public Component add(Component comp, Einfügen der Komponente comp an der Position idx int idx)
public Component add(Component comp, Einfügen der Komponente comp unter Berücksichtigung Object constr) der durch constr festgelegten Einschränkungen
public Component getComponent(int idx) Ermitteln der Komponente an der Position idx
public Component[] getComponents() Ermitteln aller Komponenten des Containers
public int getComponentCount() Ermitteln der Anzahl der Komponenten im Container
public void remove(Component comp) Entfernen der Komponente comp aus dem Container
public void remove(int idx) Entfernen der Komponente an der Position idx
public void removeAll() Entfernen aller Komponenten aus dem Container
public void setLayout(LayoutManager mgr) Setzen des Layout-Managers mgr für den Container
public LayoutManager getLayout() Ermitteln des Layout-Managers des Containers
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 533 – 00 – TH – 03 -----------------------------------------------------------------------------------
Basisklassen der JFC-Hierachie (3) •••• Die abstrakte Klasse JComponent
◇ Diese von Container abgeleitete und im Package javax.swing enthaltene Klasse ist Basisklasse aller Swing-Komponenten-Klassen mit Ausnahme der Top-Level-Container
◇ Die Klasse passt einige der von Container und Component geerbten Methoden an die Funktionalität und die speziellen Eigenschaften des Swing-Frameworks an. Zusätzlich definiert sie Methoden, die speziell für Swing-Komponenten von Bedeutung sind
◇ U.a. besitzen Swing-Komponenten die folgenden bei AWT-Komponenten nicht vorhandenen Besonderheiten :
▻ Swing-Komponenten können mit einer Umrandung versehen werden. Die Umrandung wird durch ein Objekt einer das Interface Border implementierenden Klasse festgelegt. Zur Erzeugung derartiger Border-Objekte stehen statische Methoden der Klasse BorderFactory zur Verfügung.
▻ Der Hintergrund von Swing-Komponenten kann durchsichtig (nicht-opak) oder undurchsichtig (opak) sein. AWT-Komponenten besitzen immer einen undurchsichtigen Hintergrund. In der Klasse JComponent ist als Default durchsichtig (nicht-opak) festgelegt. Allerdings hängt der tatsächliche Defaultwert dieser Eigenschaft bei den abgeleiteten Swing-Klassen i.a. von dem jeweils eingesetzten LaF ab.
▻ Swing-Komponenten können mit einem Tooltip ausgestattet werden. Hierbei handelt es sich um einen mit der Komponente verknüpften Hinweistext, der angezeigt wird, wenn der Mauszeiger für kurze Zeit über der Kom- ponente verweilt.
▻ Für Swing-Komponenten können die dem Layout-Manager als Dimensionierungsvorschläge dienenden Werte für die maximale, die minimale und die bevorzugte Größe (Breite und Höhe) der Komponente sowie Vorschläge für die Ausrichtung einer Komponente (in x- und y-Richtung) explizit gesetzt werden. Die entsprechenden Ermitt- lungs-Methoden (get...(), z.B. getMaximumSize()) sind bereits in der Klasse Component definiert.
◇ Zu den wichtigsten der speziellen Swing-Komponenten-Methoden gehören : (die Methoden zum Registrieren von Listener-Objekten für die Event-Behandlung sind nicht mit aufgeführt )
public void setBorder(Border bord) Setzen des Border-Objekts bord als Umrandung für die Komponente
public Border getBorder() Ermitteln der Umrandung der Komponente
public void setOpaque(boolean opa) Setzen des Hintergrunds der Komponente auf undurch- sichtig (opa==true) bzw durchsichtig (opa==false)
public boolean isOpaque() Ermitteln, ob Hintergrund der Komponente undurchsichtig oder durchsichtig ist true, wenn undurchsichtig, false, wenn durchsichtig
public void setToolTipText(String txt) Setzen des Tooltip-Textes für die Komponente
public String getToolTipText() Ermitteln des Tooltip-Textes der Komponente
public void setMaximumSize(Dimension d) Setzen der maximalen Größe der Komponente auf die durch d gegebene Breite und Höhe. Erzeugung eines Dimension-Objekts : new Dimension(breite, hoehe)
public void setMinimumSize(Dimension d) Setzen der minimalen Größe der Komponente auf d
public void setPreferredSize(Dimension d) Setzen der bevorzugten Größe der Komponente auf d
public void setAlignmentX(float align) Setzen der Ausrichtung in hor. Richtung (0.0 ... 1.0)
public void setAlignmentY(float align) Setzen der Ausrichtung in vert. Richtung (0.0 ... 1.0)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 541 – 00 – TH – 04 ------------------------------------------------------------------------------------
Erstellung einer GUI-Anwendung in Java (1)
•••• Prinzipielle Vorgehensweise
◇ Jede GUI-Anwendung besitzt wenigstens ein Top-Level-Fenster, über das sie mit dem Anwender kommuniziert. Eine GUI-Anwendung kann auch mehrere Top-Level-Fenster besitzen.
◇ Für jedes Top-Level-Fenster wird eine eigene Klasse definiert. Der Aufbau dieser Fenster-Erzeugungs-Klasse kann unterschiedlich sein. Neben anderen bieten sich folgende Hauptvarianten an :
▻ Die Klasse instanziert ein Objekt der eingesetzten JFC-Top-Level-Container-Klasse (i.a. in ihrem Konstruktor) Dieses kann sie gegebenenfalls über eine Datenkomponente referieren.("has a container")
▻ Die Klasse ist von der eingesetzten JFC-Top-Level-Container-Klasse abgeleitet. Bei der Instanzierung der Klasse wird das Top-Level-Container-Objekt als Teilobjekt angelegt ("is a container").
◇ Für normale Anwendungsprogramme werden als Top-Level-Container-Klassen i.a. die Klassen Frame (für AWT- Anwendungen) bzw JFrame (für Swing-Anwendungen) eingesetzt.
◇ Die Konfigurierung eines Top-Level-Fensters und damit der graphischen Oberfläche erfolgt typischerweise im Konstruktor der Fenster-Erzeugungs-Klasse bzw in speziellen von diesem aufgerufenen Memberfunktionen :
▻ Gegebenenfalls explizite Erzeugung des Top-Level-Container-Objekts (s. oben)
▻ Festlegung des Erscheinungsbildes (ohne LaF, das wird i.a. von ausserhalb , z.B in der main()-Methode der Start-Klasse, festgelegt) :
▹ Setzen des Layout-Managers (wenn anders als Default)
▹ Setzen der Hintergrund- und Vordergrundfarbe (wenn anders als Default)
▹ Setzen der Schriftart (wenn überhaupt benötigt und anders als Default)
▹ Setzen der (Ausgangs-)Größe des Fensters Wenn die Fenster-Erzeugungs-Klasse von der Top-Level-Container-Klasse abgeleitet ist, wird das auch häufig von ausserhalb – nach der Instanziierung der Klasse – vorgenommen.
▹ Setzen des Titels des Fensters Dieser kann entweder dem Konstruktor der Klasse Frame bzw JFrame übergeben werden oder mittels der Memberfunktion setTitle() festgelegt werden. Auch dies erfolgt häufig von ausserhalb des Konstruktors der Fenster-Erzeugungs-Klasse, wenn diese von der Top-Level-Container-Klasse abgeleitet ist.
▻ Erzeugen, Konfigurieren und Einfügen der Komponenten-Objekte des Containers. Dies wird sinnvollerweise haeufig in eine eigene Methode ausgelagert. Zur Konfigurierung einer einzufügenden GUI-Komponente sind gegebenenfalls analoge Schritte wie bei der Konfigurierung des Top-Level-Fensters auszuführen. Je nach Komponente stehen u.U. noch zusätzliche Konfigurationsmöglichkeiten zur Verfügung (z. B. Setzen einer Umrandung) Anmerkung zum Einfügen der Komponenten: In die AWT-Top-Level-Container (Frame, Dialog, Window) werden Komponenten direkt eingefügt (mittels add()). In die Swing-Top-Level-Container ( JFrame, JDialog, JWindow) dagegen werden die Komponenten nicht direkt eingefügt. Sie verfügen über einen speziellen Einfüge-Container, die sogenannte content pane, in die alle aufzunehmenden Komponenten mittels add() einzufügen sind.
◇ Definition von Event-Listener-Klassen und Registrierung der Event-Listener-Objekte bei den einzelnen Komponenten. Dies wird ebenfalls sinnvollerweise haeufig in eine eigene Methode ausgelagert. Die Kommunikation mit dem Anwender und dem Rest des Anwendungsprogramms (Entity-Klassen) erfolgt nur über die durch die Event-Listener definierten Methoden (Callbacks !)
◇ Anzeigen des Top-Level-Containers (und aller in ihm enthaltenen Komponenten). Dies erfolgt durch Einschalten der Sichtbarkeit des Containers (Aufruf von setVisible(true)). Dies kann entweder ebenfalls im Konstruktor der Fenster-Erzeugungs-Klasse oder – wenn diese von der Top-Level- Container-Klasse abgeleitet ist – von ausserhalb erfolgen.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 542 – 00 – TH – 01 -----------------------------------------------------------------------------------
Erstellung einer GUI-Anwendung in Java (2)
•••• Beispiel einer sehr einfachen AWT-Anwendung Top-Level-Fenster (abgeleitet von Frame) mit einer Label-Komponente
// AWTSimpleFrame.java import java.awt.*; public class AWTSimpleFrame extends Frame { public AWTSimpleFrame(String title) { super(title); Label lab1 = new Label("Hallo !", Label.CENTER); add(lab1); addWindowListener(new WindowClosingAdapter()); // Registrierung eines // Event-Listeners // zum Schliessen des Fensters setSize(300,160); } public static void main(String[] args) { AWTSimpleFrame fenster = new AWTSimpleFrame("Ein sehr einfaches AWT-Fenster"); fenster.setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 543 – 00 – TH – 01 -----------------------------------------------------------------------------------
Erstellung einer GUI-Anwendung in Java (3)
•••• Beispiel einer sehr einfachen Swing-Anwendung Top-Level-Fenster (abgeleitet von JFrame) mit einer JLabel-Komponente
// SwingSimpleFrame.java import javax.swing.*; import java.awt.*; public class SwingSimpleFrame extends JFrame { private Container c; public SwingSimpleFrame(String title) { super(title); JLabel lab1 = new JLabel("Hallo !", SwingConstants.CENTER); c = getContentPane(); c.add(lab1); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(320, 160); } public static void main(String[] args) { SwingSimpleFrame fenster = new SwingSimpleFrame( "Ein sehr einfaches Swing-Fenster"); fenster.setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 551 – 00 – TH – 03 ------------------------------------------------------------------------------------
Die Klasse Color (Package java.awt)
•••• Allgemeines
◇ Objekte der Klasse Color dienen zur Beschreibung von Farben. Sie werden z.B. zum Setzen der Hintergrund- und Vordergrundfarbe von GUI-Komponenten benötigt
◇ Objekte dieser Klasse legen eine Farbe durch deren Rot- Grün- und Blau-Anteile (RGB-Werte) fest. Jeder Anteil wird durch einen int-Wert im Bereich 0 ... 255 repräsentiert. Er lässt sich auch durch einen float-Wert im Bereich 0.0 ... 1.0 angeben.
◇ Eine weitere Datenkomponente dient zur Beschreibung der Farb-Transparenz (Alpha-Wert). Auch dieser Wert wird entweder als int-Wert (Bereich 0 ... 255) oder als float-Wert (Bereich 0.0 ... 1.0) angegeben. Dabei bedeutet - der Wert 0 bzw 0.0 vollkommen durchsichtig (nicht opak), - der Wert 255 bzw 1.0 vollkommen undurchsichtig (opak)
◇ Objekte für 13 häufig verwendete Farben sind vordefiniert und stehen als Klassen-Konstante zur Verfügung : Von Color.BLACK über Color.GREEN bis Color.YELLOW •••• Konstruktoren
◇ Beliebige Color-Objekte lassen sich unter Angabe der RGB-Werte und gegebenenfalls des Alpha-Werts mit Hilfe der folgenden Konstruktoren erzeugen:
•••• Memberfunktionen zur Ermittlung der Farb-Komponenten
◇ Neben zahlreichen anderen Memberfunktionen existieren die folgenden Methoden zum Ermitteln der einzelnen Farbkomponenten eines Color-Objekts.
public Color(int r, int g, int b) Erzeugung eines Color-Objekts mit den angegebenen RGB-Werten und einem Alpha-Wert von 255 (vollkommen undurchsichtig)
public Color(float r, float g, float b) Erzeugung eines Color-Objekts mit den angegebenen RGB-Werten und einem Alpha-Wert von 1.0 (vollkommen undurchsichtig)
public Color(int r, int g, int b, Erzeugung eines Color-Objekts mit den angegebenen int a) RGB-Werten und dem angegebenen Alpha-Wert (a)
public Color(float r, float g, float b, Erzeugung eines Color-Objekts mit den angegebenen float a) RGB-Werten und dem angegebenen Alpha-Wert (a)
public int getRed() Ermittlung der Rot-Komponente im Bereich 0 ... 255
public int getGreen() Ermittlung der Grün-Komponente im Bereich 0 ... 255
public int getBlue() Ermittlung der Blau-Komponente im Bereich 0 ... 255
public int getAlpha() Ermittlung des Alpha-Werts im Bereich 0 ... 255
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 552 – 00 – TH – 02 -----------------------------------------------------------------------------------
Die Klasse Font (Package java.awt)
•••• Allgemeines
◇ Objekte der Klasse Font repräsentieren Schriftarten.
◇ Die Methode setFont() der Klasse Component dient zur Festlegung der in einer GUI-Komponente zu ver- wendenden Schriftart. Ihr ist ein Font-Objekt als Parameter zu übergeben. Wird für eine GUI-Komponente keine Schriftart explizit festgelegt (kein Aufruf der Methode setFont() oder ein Aufruf mit null als aktuellem Parameter), so erbt diese Komponente die in ihrem Container eingesetzte Schriftart. Defaultmässig wird ein systemabhängiger Standard-Font verwendet.
◇ Eine Schriftart wird durch drei Parameter festgelegt :
▻ Font-(Familien-)Name
▻ Schriftstil
▻ Schriftgröße
◇ Font-(Familien-)Name Als Font-(Familien-)Name wird i.a. ein Name für einen logischen Font angegeben, der von der Java-Laufzeitumgebung auf einen im System real vorhandenen Font (physikalischen Font) abgebildet wird. Von jedem Java-System werden die folgenden logischen Font-Familien-Namen unterstützt :
▻ "Serif" � systemspezifische Proportionalzeichensatz-Familie TimesRoman Umsetzung unter Windows : True-Type-Font Times New Roman
▻ "SansSerif" � systemspezifische Proportionalzeichensatz-Familie Helvetica Umsetzung unter Windows : True-Type-Font Arial
▻ "Monospaced" � systemspezifische Nichtproportionalzeichensatz-Familie Courier Umsetzung unter Windows : True-Type-Font Courier New
◇ Schriftstil Spezifizierung durch einen int-Wert. Hierfür sind in der Klasse Font die folgenden Konstanten definiert :
▻ Font.PLAIN (0) normale Schrift
▻ Font.BOLD (1) fette Schrift
▻ Font.ITALIC (2) kursive Schrift Die Schriftstile Font.BOLD und Font.ITALIC können auch miteinander kombiniert werden (Addition oder bitweis-Oder) � fette und kursive Schrift.
◇ Schriftgröße Angabe in Punkt (Pt) durch einen int-Wert. Übliche Punktgrößen für normale Textdarstellung : 10 oder 12 Pt. •••• Konstruktor
◇ Font-Objekte können mit Hilfe des folgenden Konstruktors erzeugt werden : •••• Memberfunktionen zur Ermittlung der Font-Komponenten
◇
public Font(String name, int style, int size) Erzeugung eines neuen Font-Objekts mit dem Namen name, Stil style und Größe size
public String getName() Ermittlung des logischen Font-Familien-Namens
public String getFamily() Ermittlung des physikalischen Font-Familien-Namens
public int getStyle() Ermittlung des Schriftstils
public int getSize() Ermittlung der Schriftgröße in Punkt
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 553 – 01 – TH – 04 -----------------------------------------------------------------------------------
Layout-Manager in Java (1)
•••• Allgemeines
◇ Üblicherweise wird die Anordnung (Größe und Position) der in einem Container enthaltenen Komponenten durch einen Layout-Manager vorgenommen. Prinzipiell können die einzelnen Komponenten zwar "Hinweise" zu ihrer Größe, Position und Ausrichtung enthalten, diese müssen aber nicht vom Layout-Manager berücksichtigt werden. Vielmehr hat dieser das "letzte Wort" bezüglich der Anordnung.
◇ Es ist auch möglich, auf einen Layout-Manager zu verzichten und mit absoluter Positionierung zu arbeiten. Dies erfor- dert dann eine genaue Festlegung der Größe und der Position jeder einzelnen Komponente und führt zu Anpassungs- problemen, wenn die Größe des Top-Level-Containers bzw die Ausführungs-Plattform verändert wird
◇ Ein Layout-Manager ist ein Objekt einer Klasse, die das Interface LayoutManager (Package java.awt) implementiert. Dieses Interface definiert Methoden, die für die Anordnung von GUI-Komponenten innerhalb eines Containers benötigt werden.
◇ Für erweiterte Layout-Fähigkeiten ist das von LayoutManager abgeleitete Interface LayoutManager2 definiert. Es enthält Methoden, die es einem Layout-Manager ermöglichen, durch contraints-Objekte festgelegte Anord- nungs-Beschränkungen / -Vorgaben explizit zu berücksichtigen. contraints-Objekte (häufig String-Objekte) spezifizieren wie und wo Komponenten in das Layout einzufügen sind.
◇ Die Java-Bibliothek stellt eine Reihe von Layout-Manager-Klassen zur Verfügung. Die einzelnen Klassen unterscheiden sich insbesondere hinsichtlich der Unterteilung der Gesamtfläche eines Containers in verschiedene Bereiche und die Zuordnung dieser Bereiche zu den im Container enthaltenen Komponenten. Einige Layout-Manager passen dabei die Komponenten in ihrer Groesse an oder fügen Zwischenräume zwischen ihnen ein. Einige von ihnen implementieren nur das Interface LayoutManager, andere das Interface LayoutManager2. Layout-Manager-Klassen sind sowohl im Package java.awt als auch im Package javax.swing definiert Die am häufigsten verwendeten Layout-Manager-Klassen sind :
▻ BorderLayout (Package java.awt)
▻ FlowLayout (Package java.awt)
▻ GridLayout (Package java.awt)
▻ BoxLayout (Package javax.swing)
▻ GridBagLayout (Package java.awt)
◇ Defaultmässig ist in den meisten GUI-Container-Klassen das BorderLayout eingestellt. Ausnahmen : - Für die Klassen Panel und JPanel ist FlowLayout voreingestellt. - Für die Klasse Box (Package javax.swing) ist BoxLayout voreingestellt Ein anderer Layout-Manager kann mit der in der Klasse Container definierten Methode void setLayout(LayoutManager mgr) für jedes Container-Objekt individuell festgelegt werden Dabei lassen sich die im Package javax.swing definierten Layout-Manager-Klassen nur für Swing-Komponenten einsetzen, während die im Package java.awt enthaltenen Layout-Manager-Klassen sowohl für AWT- als auch für Swing-Komponenten Anwendung finden.
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 553 – 02 – TH – 02 -----------------------------------------------------------------------------------
Layout-Manager in Java (2)
•••• Die Klasse BorderLayout (Package java.awt)
◇ Dieser Layout-Manager teilt den Container in fünf Gebiete ein : "Norden", "Süden", "Westen", Osten" und "Zentrum". In jedes dieser Gebiete kann er genau eine Komponente einfügen.
◇ Die einzelnen Komponenten werden in ihrer Größe so angepasst, dass sie insgesamt den gesamten Container ausfüllen. Allerdings können sowohl horizontale als auch vertikale Abstände zwischen den Komponenten festgelegt werden. Die Komponenten im "Norden" und "Süden" bekommen ihre bevorzugte Höhe und werden in der Breite an die Con- tainergröße angepasst Die Komponenten im "Westen" und "Osten" bekommen dagegen ihre bevorzugte Breite und werden in der Höhe an den Container angepasst. Die Komponente im "Zentrum" wird sowohl in der Höhe als auch in der Breite an den verbleibenden Bereich angepasst.
◇ Konstruktoren :
◇ Beim Einfügen einer Komponente in einen Container (mittels add()) ist üblicherweise das Gebiet, in dem sie platziert werden soll, anzugeben. Für diese Angabe sind die folgenden in der Klasse BorderLayout definierten (String-)Konstanten zu verwenden : - BorderLayout.NORTH
- BorderLayout.SOUTH
- BorderLayout.WEST
- BorderLayout.EAST
- BorderLayout.CENTER Beispiel : Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add(new Button("Okay"), BorderLayout.SOUTH); Wird keine Gebietsangabe beim Einfügen angegeben, wird die Komponente im "Zentrum" platziert.
◇ Wird die Größe des Containers geändert (z.B. durch Ziehen mit der Maus), so bleibt die Höhe der Komponenten im "Norden" und "Süden" sowie die Breite der Komponenten im "Westen und "Osten" unverändert, während die jeweils andere Dimension dieser Komponenten sowie beide Dimensionen der Komponente im "Zentrum" an die Größe des Containers angepasst werden.
◇ Beispiel : Border-Layout eines JFrame-Containers mit fünf JButton-Komponenten
public BorderLayout() Erzeugung eines BorderLayout-Objekts, das die Kom- ponenten ohne Zwischenabstände anordnet
public BorderLayout(int hgap, int vgap) Erzeugung eines BorderLayout-Objekts, das die Kom- ponenten mit dem horizontalen Abstand hgap und dem vertikalen Abstand vgap anordnet (Abstaende in Pixel)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 553 – 03 – TH – 01 -----------------------------------------------------------------------------------
Layout-Manager in Java (3) •••• Demonstrationsbeispiel zu Layout-Manager (hier : BorderLayout)
// LayoutDemo.java import java.awt.*; import javax.swing.*; public class LayoutDemo extends JFrame { Container c; JButton[] ba; String titel; public LayoutDemo() { c=getContentPane(); titel = "LayoutDemo : "; ba = new JButton[5]; for (int i=0; i<ba.length; i++) { ba[i] = new JButton("Button "+(i+1)); ba[i].setAlignmentX(Component.CENTER_ALIGNMENT); } ba[2].setText(ba[2].getText()+" with long title"); ba[2].setFont(new Font("Serif", Font.ITALIC|Font.BOLD, 12)); ba[2].setBackground(Color.ORANGE); useBorderLayout(); //useFlowLayout(); //useGridLayout(); //useBoxLayout(); setTitle(titel); setSize(300, 170); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } private void useBorderLayout() // BorderLayout ist Default bei JFrame { c.add(ba[0], BorderLayout.NORTH);
c.add(ba[1], BorderLayout.SOUTH);
c.add(ba[2], BorderLayout.CENTER);
c.add(ba[3], BorderLayout.WEST); c.add(ba[4], BorderLayout.EAST);
titel+="BorderLayout";
}
private void useFlowLayout() { // } private void useGridLayout() { // } private void useBoxLayout() { // } public static void main(String[] args) { new LayoutDemo().setVisisble(true); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 553 – 04 – TH – 02 -----------------------------------------------------------------------------------
Layout-Manager in Java (4)
•••• Die Klasse FlowLayout (Package java.awt)
◇ Dieser Layout-Manager fügt die Komponenten "fliessend" zeilenweise von links nach rechts in den Container ein. Dabei bedeutet "fliessend", dass die Komponenten solange in der Reihenfolge ihres Einfügens nebeneinander platziert werden, bis kein Platz mehr für die nächste Komponente vorhanden ist. Dann wird das Einfügen analog in der nächsten Reihe fortgesetzt.
◇ Die Komponenten werden in ihrer bevorzugten Größe (Breite und Höhe) dargestellt. Defaultmässig werden die in einer Reihe befindlichen Komponenten zentriert ausgerichtet. Zwischen den Komponenten wird sowohl horizontal als auch vertikal ein Abstand von 5 Pixel gesetzt. Der vertikale Abstand bezieht sich dabei auf die Komponenten mit der jeweils größten Höhe. Sowohl die Ausrichtung als auch der Abstand in beiden Richtungen können geändert werden.
◇ Konstruktoren :
◇ Zur Angabe der Komponenten-Ausrichtung in den einzelnen Zeilen (Konstruktor-Parameter align) stehen in der Klasse FlowLayout die folgenden Konstanten zur Verfügung : - FlowLayout.LEFT (Ausrichtung linksbündig) - FlowLayout.RIGHT (Ausrichtung rechtsbündig) - FlowLayout.CENTER (Ausrichtung zentriert, default)
◇ Wird die Größe des Containers geändert (z.B. durch Ziehen mit der Maus), so wird die Zuordnung der Komponen- ten zu den einzelnen Zeilen entsprechend angepasst.
◇ Beispiel : Flow-Layout eines JFrame-Containers mit fünf JButton-Komponenten (Ergänzung / Modifikation des obigen Demonstrationsprogramms)
public FlowLayout() Erzeugung eines FlowLayout-Objekts, mit den Default- einstellungen (zentrierte Ausrichtung und vertikaler und horizontaler Abstand von 5 Pixel)
public FlowLayout(int align) Erzeugung eines FlowLayout-Objekts, mit einer durch align festgelegten Ausrichtung und einem vertikalen und horizontalen Abstand von 5 Pixel
public FlowLayout(int align, int hgap, Erzeugung eines FlowLayout-Objekts, mit einer durch int vgap) align festgelegten Ausrichtung und einem durch hgap (horizontal) und vgap (vertikal) gegebenen Abstand
private void useFlowLayout() { c.setLayout(new FlowLayout()); for (int i=0; i<ba.length; i++) c.add(ba[i]); titel+="FlowLayout"; }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 553 – 05 – TH – 02 -----------------------------------------------------------------------------------
Layout-Manager in Java (5)
•••• Die Klasse GridLayout (Package java.awt)
◇ Dieser Layout-Manager teilt die Containerfläche in gitter- bzw tabellenartig angeordnete Zellen auf. Die Zellen sind Rechtecke gleicher Größe. Diese Größe ergibt sich aus der Containergröße und der Anzahl von Zeilen und Spalten. In jedem dieser Rechtecke wird genau eine Komponente platziert. Standardmässig (horizontale Ausrichtung,von links nach rechts) werden die Komponenten in der Reihenfolge ihres Einfügens zeilenweise von links nach rechts angeordnet.
◇ Die Größe der Komponenten wird an die Zellen-Größe angepasst, so dass der in der Zelle verfügbare Platz voll ausge- nutzt wird. Alle Komponenten haben somit die gleiche Größe. Defaultmässig besteht zwischen den Zellen kein Abstand. Es kann aber sowohl ein vertikaler als auch ein horizontaler Abstand festgelegt werden.
◇ Die Anzahl der Zeilen und Spalten können angegeben werden (im Konstruktor oder mittels Memberfunktionen). Wenigstens einer der beiden Werte muss von 0 verschieden sein. Der Wert 0 bedeutet "beliebig viele". Wenn beide Werte von 0 verschieden sind, wird der Wert für die Anzahl der Spalten ignoriert. In diesem Fall wird die tatsächliche Anzahl der Spalten aus der festgelegten Anzahl der Zeilen und der Komponenten-Anzahl ermittelt. Die explizite Angabe einer Spalten-Anzahl beeinflusst das Layout nur dann, wenn für die Anzahl der Zeilen 0 angege- ben wird. Wird weder die Anzahl der Zeilen noch die Anzahl der Spalten explizit festgelegt, wird die Zeilenzahl defaultmässig auf 1 gesetzt. Die Anzahl der Spalten ergibt sich dann aus der Anzahl der Komponenten.
◇ Konstruktoren :
◇ Wird die Größe des Containers geändert (z.B. durch Ziehen mit der Maus), so wird – bei gleichbleibender Zeilen- und Spaltenzahl – die Größe der Zellen und damit die Größe der Komponenten an die jeweilige Gesamtgröße des Containers angepasst.
◇ Beispiel : Grid-Layout eines JFrame-Containers mit fünf JButton-Komponenten (3 Zeilen, 2 Spalten) (Ergänzung / Modifikation des obigen Demonstrationsprogramms)
public GridLayout() Erzeugung eines GridLayout-Objekts, mit einer Zeile, beliebig vielen Spalten, kein Abstand zwischen den Zellen
public GridLayout(int rows, int cols) Erzeugung eines GridLayout-Objekts, mit rows Zeilen und cols Spalten (tatsächliche Auswirkung siehe oben), kein Abstand zwischen den Zellen
public GridLayout(int rows, int cols, Erzeugung eines GridLayout-Objekts, mit rows Zeilen int hgap, int vgap) und cols Spalten (siehe oben), sowie einem durch hgap (horizontal) und vgap (vertikal) gegebenen Zellen-Abstand
private void useGridLayout() { c.setLayout(new GridLayout(3,2)); for (int i=0; i<ba.length; i++) c.add(ba[i]); titel+="GridLayout(3,2)"; }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 553 – 06 – TH – 02 ------------------------------------------------------------------------------------
Layout-Manager in Java (6)
•••• Die Klasse BoxLayout (Package javax.swing)
◇ Dieser Layout-Manager ordnet die Komponenten – gemäß ihrer Einfüge-Reihenfolge - entweder horizontal in einer Zeile oder vertikal in einer Spalte an. Die Anordnungs-Achse ist jeweils festzulegen (kein Default).
◇ Er berücksichtigt hierbei sowohl die für die einzelnen Komponenten eingestellten Größen-Parameter (minimale, maxi- male und bevorzugte Größe) als auch deren festgelegte vertikale und horizontale Ausrichtung. Grundsätzlich versucht er die Komponenten in ihrer bevorzugten Größe darzustellen. Sind bei vertikaler Anordnung die bevorzugten Breiten der Komponenten unterschiedlich, wird versucht, unter Be- rücksichtigung der jeweiligen maximalen Breiten, die Breite aller Komponenten an die größte bevorzugte Breite anzu- passen. Ist das nicht möglich, z.B. weil die maximalen Größen es nicht zulassen, werden die Komponenten in ihrer bevorzugten Breite dargestellt. Die horizontale Ausrichtung der Komponenten (sowohl untereinander als auch innerhalb des Contai- ners) richtet sich nach deren – defaultmässig vorgegebener bzw explizit gesetzter – horizontaler (X-) Ausrichtung. Analoges gilt für die horizontale Anordung. Werden die Komponenten mit unterschiedlicher Höhe dargestellt, richtet sich ihre vertikale Ausrichtung nach der für die einzelnen Komponenten eingestellten vertikalen (Y-) Ausrichtung (Default ist.i.a. zentriert)
◇ Zwischen den Komponenten wird kein Abstand eingefügt. Zum Erzeugen von Abständen können spezielle unsichtbare Füll-Komponenten eingesetzt werden.
◇ Konstruktor :
◇ Zur Festlegung der Anordnungs-Achse (Konstruktor-Parameter axis) stehen in der Klasse BoxLayout die folgen- den Konstanten zur Verfügung : - BoxLayout.X_AXIS (horizontale Anordnung, in einer Zeile) - BoxLayout.Y_AXIS (vertikale Anordnung, in einer Spalte) - BoxLayout.LINE_AXIS (Bedeutung sprachabhängig, bei europäischen Sprachen : horizontale Anordnung) - BoxLayout.PAGE_AXIS (Bedeutung sprachabhängig, bei europäischen Sprachen : vertikale Anordnung)
◇ Bei einer Größenänderung des Containers (z.B. durch Ziehen mit der Maus), behalten die Komponenten ihre ur- sprüngliche Größe, Anordnung und Ausrichtung (zueinander und im Container).
◇ Beispiel : Box-Layout eines JFrame-Containers mit fünf JButton-Komponenten (vertikale Anordnung) (Ergänzung / Modifikation des obigen Demonstrationsprogramms)
public BoxLayout(Container con, int axis) Erzeugung eines BoxLayout-Objekts für das Container-Objekt con mit der durch axis festgelegten Anordnungs-Achse
private void useBoxLayout() { c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS)); for (int i=0; i<ba.length; i++) c.add(ba[i]); titel+="BoxLayout"; }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 554 – 01 – TH – 04 -----------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (1) •••• Umrandungen und das Interface Border (Package javax.swing.border)
◇ Swing-GUI-Komponenten (genauer : Objekte aller von JComponent abgeleiteten Klassen) können mit einer Umrandung versehen werden. Derartige Umrandungen können u.a. dazu dienen : - GUI-Komponenten mit einer Dekoration zu versehen - um rahmenlose GUI-Komponenten einen Rahmen zu zeichnen - für GUI-Komponenten einen Namen anzugeben - GUI-Komponenten mit Abstandsflächen zu versehen.
◇ Umrandungen werden durch Border-Objekte beschrieben. Zum Setzen einer Umrandung muß die in JComponent definierte Memberfunktion setBorder() mit einem Border-Objekt als Parameter für das entsprechende GUI-Komponenten-Objekt aufgerufen werden.
◇ Border-Objekte sind Objekte von Klassen, die das Interface Border implementieren. •••• Klassen für Border-Objekte
◇ In der Java-Standard-Bibliothek – u.a. im Package javax.swing.border – sind zahlreiche Klassen, die das Interface Border implementieren, definiert. Einige der im Package javax.swing.border enthaltenen Klassen sind :
▻ AbstractBorder abstrakte Basisklasse für konkrete Border-Klassen
▻ EmptyBorder Klasse für "leere" Umrandungen � Abstandsflächen
▻ LineBorder Klasse für Umrahmungen mit "normalen" Linien
▻ EtchedBorder Klasse für Umrahmungen mit eingeprägten bzw herausgearbeiteten Linien
▻ TitledBorder Klasse für mit einem Titel versehene Umrandungen
▻ CompoundBorder Klasse zur Zusammenfassung von zwei Umrandungen zu einer einzigen
◇ Es ist auch möglich eigene Border-Klassen zu definieren. Diese sind zweckmässigerweise von der Klasse AbstractBorder abzuleiten. •••• Anwendungung von Umrandungen
◇ Prinzipiell können Umrandungen um jedes Objekt einer von JComponent abgeleiteten Klasse gesetzt werden.
◇ Jedoch arbeitet die LaF-Implementierung vieler Standard-Swing-Komponenten nicht sehr gut mit explizit gesetzten Umrandungen. Es wird daher empfohlen, Umrandungen grundsätzlich nur für JPanel- und JLabel-Komponenten zu verwenden. Bei Komponenten dieser Klassen treten keine Probleme auf.
◇ Sollen andere Swing-Komponenten mit einer Umrandung versehen werden, so sollten diese zweckmässigerweise in jeweils eine JPanel-Komponente eingebettet werden und um diese dann die Umrandung gesetzt werden. •••• Erzeugung von Border-Objekten
◇ Ein Border-Objekt kann von mehreren GUI-Komponenten-Objekten gemeinsam genutzt werden. Daher ist es üblich und zweckmässig , Border-Objekte nicht mittels eines new-Ausdrucks zu erzeugen, sondern hierfür statische Erzeugungs-Methoden der Klasse BorderFactory (Package javax.swing) einzusetzen (Verwendung von Border-Objekten als Singletons).
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 554 – 02 – TH – 05 ------------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (2) •••• Die Klasse BorderFactory (Package javax.swing)
◇ Die Klasse BorderFactory stellt u.a. die folgenden statischen Erzeugungs-Methoden für Border-Objekte bereit (Auswahl) :
public static Border createEmptyBorder(int top, int left, int bottom, int right) Erzeugung eines EmptyBorder-Objekts mit den durch die Parameter festgelegten Größen (in Pixel) public static Border createLineBorder(Color col, int thick) Erzeugung eines LineBorder-Objekts, das die Farbe col und die Linien-Stärke thick (in Pixel) verwendet public static Border createLineBorder(Color col) Erzeugung eines LineBorder-Objekts, das die Farbe col und einen Defaultwert für die Linien-Stärke verwendet public static Border createEtchedBorder() Erzeugung eines EtchedBorder-Objekts für eingeprägte (etched-in) Umrandungen, das die aktuelle Hintergrundfarbe des zu umrandenden Objekts für Hervorhebungen und Abschattungen verwendet public static Border createEtchedBorder(int type) Erzeugung eines EtchedBorder-Objekts für den durch type festgelegten Umrandungstyp, das die aktuelle Hinter- grundfarbe des zu umrandenden Objekts für Hervorhebungen und Abschattungen verwendet Zulässige Werte für type : EtchedBorder.RAISED herausgearbeitete Umrandung (etched-out) EtchedBorder.LOWERED eingeprägte Umrandung (etched-in) public static Border createEtchedBorder(int type, Color highlight, Color shadow) Erzeugung eines EtchedBorder-Objekts für den durch type festgelegten Umrandungstyp, das die Farbe highlight für Hervorhebungen und die Farbe shadow für Abschattungen verwendet public static TitledBorder createTitledBorder(String str) Erzeugung eines TitledBorder-Objekts, das die Beschriftung str und Defaultwerte für die übrigen Kenngrößen verwendet. Diese Defaultwerte sind : eingeprägte (?) Umrandung, Text auf oberem Rand, linksbündig, Font und Textfarbe durch die Defaultwerte des aktuellen LaF bestimmt public static TitledBorder createTitledBorder(Border bord, String str) Erzeugung eines TitledBorder-Objekts aus dem existierenden Border-Objekt bord, das die Beschriftung str sowie Defaultwerte für die Textposition (oberer Rand), die Textausrichtung (linksbündig) und Font und Textfarbe (Defaultwerte des aktuellen LaF) verwendet. public static TitledBorder createTitledBorder(Border bord, String str, int just,
int pos) Erzeugung eines TitledBorder-Objekts aus dem existierenden Border-Objekt bord, das die Beschriftung str sowie die Textposition pos, die Textausrichtung just und Defaultwerte für Font und Textfarbe (Defaultwerte des aktuellen LaF) verwendet. Zulässige Werte für just und pos siehe Java-API-Doc public static TitledBorder createTitledBorder(Border bord, String str, int just,
int pos, Font fnt, Color col) Erzeugung eines TitledBorder-Objekts aus dem existierenden Border-Objekt bord, das die Beschriftung str sowie die Textposition pos, die Textausrichtung just, den Font fnt und die Farbe col verwendet. Zulässige Werte für just und pos siehe Java-API-Doc public static CompoundBorder createCompoundBorder(Border out, Border in) Erzeugung eines CompoundBorder-Objekts aus den existierenden Border-Objekten out (äussere Umrandung) und in (innere Umrandung)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 554 – 03 – TH – 02 ------------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (3) •••• Demonstrationsprogramm zu Umrandungen
// MultiBorderDemo.java import java.awt.*; import javax.swing.*; import javax.swing.border.*; public class MultiBorderDemo extends JFrame { Container c; JButton[] ba; String titel; public MultiBorderDemo(int sel) { c=getContentPane(); c.setLayout(new FlowLayout()); titel = "MultiBorderDemo"; JPanel[] pa = new JPanel[5]; for (int i=0; i<pa.length; i++) { pa[i] = new JPanel(); JButton but = new JButton("Button "+(i+1)); if(i==2) { but.setText(but.getText()+" with long title"); but.setFont(new Font("Serif", Font.ITALIC|Font.BOLD, 12)); but.setBackground(Color.ORANGE); } pa[i].add(but); switch (sel) { case 1 : pa[i].setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); break; case 2 : pa[i].setBorder(BorderFactory.createEtchedBorder()); break; case 3 : pa[i].setBorder(BorderFactory.createTitledBorder("button")); break; case 4 : Border inbord = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); Border outbord = BorderFactory.createLineBorder(Color.GREEN, 5); pa[i].setBorder(BorderFactory.createCompoundBorder(outbord, inbord)); break; default : break; } c.add(pa[i]); } setTitle(titel); setSize(300, 240); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { if (args.length==1) new MultiBorderDemo(Integer.parseInt(args[0])).setVisible(true); else new MultiBorderDemo(0).setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 554 – 04 – TH – 01 -----------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (4) •••• Beispiele für Umrandungen (vom Demonstrationsprogramm MultiBorderDemo erzeugte Fenster) keine Umrandung Umrandung mit EmptyBorder Umrandung mit EtchedBorder Umrandung mit TitledBorder Umrandung mit CompoundBorder aus Etchedborder und LineBorder
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 561 – 00 – TH – 07 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (1) •••• Die Klasse JFrame (Package javax.swing)
◇ Wichtigste Swing-Top-Level-Container-Klasse
◇ Im Unterschied zur AWT-Top-Level-Container-Klasse Frame, von der JFrame abgeleitet ist, werden in einen JFrame-Container die Komponenten nicht direkt eingefügt. Vielmehr besitzt jeder JFrame-Container, wie jeder andere Swing-Top-Level-Container, einen speziellen Einfüge-Container, die sogenannte content pane. Die content pane umfasst den gesamten "normalen" Einfüge-Bereich des Top-Level-Containers. In den Top-Level- Container aufzunehmende Komponenten werden in seine content pane eingefügt. Auch das Setzen eines Layout-Managers erfolgt in der content pane und nicht direkt im JFrame-Container. Anmerkung : Ab dem JDK 5.0 sind die Methoden add(), remove() und setLayout() für die Klasse JFrame so überschrieben, dass sie implizit die content pane verwenden. Sie können damit direkt für JFrame- Container aufgerufen werden.
◇ Zusätzlich kann ein JFrame-Container über eine Menü-Leiste verfügen. Falls vorhanden, befindet sich diese ausser- halb der content pane. Sie wird direkt in den Top-Level-Container eingefügt. Weiterhin kann ein JFrame-Container eine Werkzeugleiste besitzen. Diese wird analog zu anderen Komponenten in die content pane eingefügt.
◇ Als weiterer Unterschied zur AWT-Klasse Frame ist in der Klasse JFrame bereits – ohne explizite Registrierung eines Window-Listeners – eine Reaktions-Funktionalität auf das Schliessen des Fensters implementiert. Die genaue Reaktion kann mittels der Memberfunktion public void setDefaultCloseOperation(int op)
festgelegt werden. Als gültige Werte für den Parameter op können die folgenden Konstanten verwendet werden : - WindowConstants.DO_NOTHING_ON_CLOSE keine Reaktion - WindowConstants.HIDE_ON_CLOSE das Fenster verstecken (unsichtbar machen), Default - WindowConstants.DISPOSE_ON_CLOSE das Fenster verstecken und zerstören - JFrame.EXIT_ON_CLOSE das Programm beenden (mittels System.exit(0))
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl) *) geerbt von Frame **) geerbt von Window
◇ Beispiel zum Einfügen von Komponenten JFrame frame = new JFrame();
Container c = frame.getContentPane();
c.setLayout(new FlowLayout()); // ab JDK 5.0 auch : frame.setLayout(...) c.add(new JLabel("Hallo")); // ab JDK 5.0 auch : frame.add(...)
public JFrame() Erzeugung eines JFrame-Objekts ohne Titel, das durch das Objekt repräsen- tierte Fenster ist unsichtbar
public JFrame(String title) Erzeugung eines JFrame-Objekts mit dem Titel title, das durch das Objekt repräsentierte Fenster ist unsichtbar
public Container getContentPane() Ermitteln der content pane
public void setDefaultCloseOperation(int op) Setzen der Reaktion auf das Schliessen des Fensters
public void setJMenuBar(JMenuBar menu) Einfügen der Menuleiste menu
public void setTitle(String title) *) Setzen des Titels auf title
public void dispose() **) Zerstören des Fensters
public void pack() Anpassen der Fenstergröße so, dass alle darin enthaltenen Komponenten gerade Platz haben **) (Berechnung des Platzbedarfs an Hand der bevorzugten Größe der Komponenten)
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 562 – 00 – TH – 08 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (2)
•••• Die Klasse JDialog (Package javax.swing)
◇ Diese Top-Level-Container-Klasse wird typischerweise dazu benutzt, temporär auf dem Bildschirm erscheinende Fenster zu erzeugen, die für einen kurzen Dialog mit dem Benutzer vorgesehen sind (� Dialog-Fenster, Dialog-Box)
◇ Ein Dialog-Fenster ist üblicherweise an einen JFrame-Container oder ein anderes Dialog-Fenster gebunden ("Besitzer" des Dialog-Fensters). Es wird zusammen mit seinem "Besitzer" ikonifiziert/de-ikonifiziert oder geschlossen.
◇ Dialog-Fenster können modal gestaltet werden. Das bedeutet, dass während der Sichtbarkeit eines Dialog-Fensters alle anderen Fenster des Programms (also auch sein "besitzendes" Fenster) für Benutzereingaben gesperrt ist. Die anderen Fenster können erst wieder verwendet werden, wenn der Dialog abgewickelt, d.h. das Dialog-Fenster wieder geschlossen ist.
◇ Wie ein JFrame-Objekt besitzt auch ein JDialog-Objekt eine content pane. In diese – und nicht direkt in das JDialog-Objekt – müssen aufzunehmende Komponenten eingefügt werden. Auch ein eventueller Layout-Manager ist ebenfalls in der content pane zu setzen. Anmerkung : ab dem JDK 5.0 erfolgt dies implizit durch die für JDialog entsprechend überladenen Methoden add() und setLayout() (sowie das Entfernen durch remove())
◇ Ein JDialog-Objekt kann auch eine Menue-Leiste besitzen. Diese wird – wie bei JFrame-Objekten – direkt in den Top-Level-Container und nicht in die content pane eingefügt.
◇ Konstruktoren (Auswahl) Es existieren weitere Konstruktoren, mit denen statt eines Frame-(JFrame)-Objekts ein Dialog-(JDialog-) Objekt als "Besitzer" festgelegt wird.
◇ Memberfunktionen (Auswahl) Die als Auswahl bei der Klasse JFrame angegebenen Memberfunktionen existieren auch für die Klasse JDialog : public Container getContentPane() public void setDefaultCloseOperation(int op) Der Wert EXIT_ON_CLOSE für op ist nicht zulässig public void setJMenuBar(JMenuBar menu) public setTitle(String title) *) geerbt von Dialog public void dispose() **) geerbt von Window public void pack() **) geerbt von Window Einige weitere Memberfunktionen (geerbt von Dialog) :
public JDialog() Erzeugung eines nicht-modalen JDialog-Objekts ohne Titel und ohne explizit spezifizierten "Besitzer". Ein verborgenes Frame-Objekt wird implizit als "Besitzer" gesetzt
public JDialog(Frame owner) Erzeugung eines nicht-modalen JDialog-Objekts ohne Titel und dem Frame-(JFrame-)Objekt owner als "Besitzer"
public JDialog(Frame owner, Erzeugung eines nicht-modalen JDialog-Objekts mit dem Titel tit und String tit) dem Frame-(JFrame-)Objekt owner als "Besitzer"
public JDialog(Frame owner, Erzeugung eines JDialog-Objekts ohne Titel und dem Frame-(JFrame-) boolean mod) Objekt owner als "Besitzer". Der Parameter mod bestimmt die Modalität : modal, wenn true, nicht-modal, wenn false
public JDialog(Frame owner, Erzeugung JDialog-Objekts mit dem Titel tit und dem Frame- String tit, (JFrame-) Objekt owner als "Besitzer". Der Parameter mod bestimmt die boolean mod) Modalität : modal, wenn true, nicht-modal, wenn false
public void setModal(boolean mod) Setzen der Modalität auf modal, wenn mod == true
public boolean isModal() Ermittlung der Modalität, Rückgabewert : true, wenn modal, false andernfalls
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 563 – 01 – TH – 03 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (3-1) •••• Die Klasse JOptionPane (Package javax.swing)
◇ Diese Klasse ermöglicht auf relativ einfache Art und Weise die Erzeugung einfacher Standard-Dialog-Fenster.
◇ Die erzeugbaren Standard-Dialog-Fenster informieren den Programmbenutzer über irgendetwas und/oder fordern ihn zu einer Eingabe auf.
◇ Die erzeugbaren Standard-Dialog-Fenster sind modal und können in der Größe nicht verändert werden.
◇ Als einfachste Möglichkeit zur Dialog-Fenster-Erzeugung stehen eine Reihe statischer Methoden zur Verfügung. Diese Methoden
▻ erzeugen ein weitgehend vorkonfiguriertes Dialog-Fenster, stellen es dar,
▻ warten auf eine zum Schliessen des Fensters führende Benutzeraktion (Schaltknopf-Betätigung, String-Eingabe)
▻ und liefern gegebenenfalls das Ergebnis der Benutzeraktion als Funktionswert zurück.
◇ Einige statische Klassen-Methoden als Beispiele : Der bei allen Methoden vorhandene Parameter parent legt die Komponente fest, für die der Dialog jeweils aus- geführt wird (null ist zulässig)
public static void showMessageDialog(Component parent, Object msg,
String title, int typeMsg) Erzeugen eines Meldungs-Dialog-Fensters mit dem Titel title, das die Meldung msg (meist ein String) ausgibt und ein durch den Meldungs-Typ typeMsg festgelegtes Default-Icon darstellt. Zulässige Werte für den Meldungs-Typ typeMsg : JOptionPane.ERROR_MESSAGE JOptionPane.INFORMATION_MESSAGE JOptionPane.WARNING_MESSAGE JOptionPane.QUESTION_MESSAGE
JOptionPane.PLAIN_MESSAGE (kein Icon) public static void showMessageDialog(Component parent, Object msg) Erzeugen eines Meldungs-Dialog-Fensters mit dem Titel "Message", das die Meldung msg (meist ein String) aus- gibt und das Default-Icon für den Typ INFORMATION_MESSAGE darstellt public static int showConfirmDialog(Component parent, Object msg,
String title, int typeOpt) Erzeugen eines Bestätigungs-Dialog-Fensters mit dem Titel title, das die Meldung msg (meist ein String) ausgibt und das Icon für QUESTION_MESSAGE sowie die durch den Options-Typ typeOpt festgelegten Options-Schalt- knöpfe darstellt und auf die Auswahl eines Schaltknopfes wartet. Zulässige Werte für den Options-Typ typeOpt : JOptionsPane.YES_NO_CANCEL_OPTION JOptionsPane.YES_NO_OPTION JOptionsPane.OK_CANCEL_OPTION
JOptionsPane.DEFAULT_OPTION (nur OK) Der vom Benutzer ausgewählte Options-Schaltknopf bestimmt den zurückgegebenen Funktioswert (z.B. YES_OPTION) public static int showConfirmDialog(Component parent, Object msg) Erzeugen eines Bestätigungs-Dialog-Fensters mit einem Default-Titel, das die Meldung msg (meist ein String) ausgibt und das Icon für QUESTION_MESSAGE sowie die Schaltknöpfe für den Options-Typ YES_NO_CANCEL_OPTION darstellt und auf die Auswahl eines Schaltknopfes wartet. Der vom Benutzer ausgewählte Options-Schaltknopf bestimmt den zurückgegebenen Funktioswert (z.B. YES_OPTION)
public static String showInputDialog(Component parent, Object msg) Erzeugen eines Frage-Dialog-Fensters mit dem Titel "Input" (bzw "Eingabe"), das die Meldung msg (meist ein String) ausgibt, das Icon für QUESTION_MESSAGE darstellt und auf die Eingabe eines Strings wartet. Der vom Benutzer eingegebene String wird als Funktionswert zurückgegeben.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 563 – 02 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (3-2) •••• Beispiele für von JOptionPane erzeugte Standard-Dialog-Fenster
// Meldungs-Dialog : Fehler-Meldung JOptionPane.showMessageDialog(this, "Lesefehler !", "Eine Fehler-Meldung", JOptionPane.ERROR_MESSAGE);
// Meldungs-Dialog : Information JOptionPane.showMessageDialog(this, "Die Festplatte ist zerstoert!", "Eine Information", JOptionPane.INFORMATION_MESSAGE);
// Meldungs-Dialog : Warnung JOptionPane.showMessageDialog(this, "Hoeren Sie auf !", "Eine Warnung", JOptionPane.WARNING_MESSAGE);
// Meldungs-Dialog : Frage JOptionPane.showMessageDialog(this, "Wollen Sie das wirklich ?", "Eine Frage", JOptionPane.QUESTION_MESSAGE);
// Bestätigungs-Dialog // Default-Titel und // Default-Options-Typ int opt; opt = JOptionPane.showConfirmDialog(this, "Was wollen Sie ?");
// Frage-Dialog // Default-Titel String name; name = JOptionPane.showInputDialog(this, "Ihr Name ? ");
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 564 – 00 – TH – 02 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (4) •••• Die Klasse JLabel (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von Beschriftungs-Objekten.
◇ Im Unterschied zu den AWT-Label-Objekten können JLabel-Objekte nicht nur Text, sondern auch Bilder dar- stellen (auch beides kombiniert)
◇ Die Ausrichtung sowohl des Textes als auch des Bildes innerhalb des Darstellungsbereichs eines JLabel-Objekts kann festgelegt werden. Default-Ausrichtung für Text : horizontal linksbündig, vertikal zentriert Default-Ausrichtung für Bilder : horizontal und vertikal zentriert Explizite Festlegung der Ausrichtung : SwingConstants.CENTER (zentriert) SwingConstants.RIGHT (rechtsbündig) SwingConstants.LEFT (linksbündig) SwingConstants.TOP (obenbündig) SwingConstants.BOTTOM (untenbündig)
◇ JLabel-Objekte können nicht auf vom Benutzer ausgelöste Ereignisse (Eingaben) reagieren.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl)
◇ Anmerkungen zu darzustellenden Bildern
▻ Bilder werden als Instanzen des Interfaces Icon (Package javax.swing) referiert. Im Regelfall handelt es sich bei Ihnen um Objekte der dieses Interface implementierenden Klasse ImageIcon
▻ Objekte der Klasse ImageIcon (Package javax.swing) können aus einer Bild-Datei erzeugt werden mit dem Konstruktor : public ImageIcon(String dateipfad) Der Parameter dateipfad spezifiziert die Bild-Datei.
public JLabel(String text) Erzeugung eines JLabel-Objekts mit dem Text text, der Text ist horizontal linksbündig ausgerichtet
public JLabel(String text, int halign) Erzeugung eines JLabel-Objekts mit dem Text text, der Text ist horizontal gemäß halign ausgerichtet
public JLabel(Icon image) Erzeugung eines JLabel-Objekts mit dem Bild image, das Bild ist horizontal zentriert ausgerichtet
public JLabel(Icon image, int halign) Erzeugung eines JLabel-Objekts mit dem Bild image, das Bild ist horizontal gemäß halign ausgerichtet
public String getText() Rückgabe des dargestellten Textes
public Icon getIcon() Rückgabe des dargestellten Bildes
public void setText(String text) Setzen des darzustellenden Textes auf text
public void setIcon(Icon image) Setzen des darzustellenden Bildes auf image
public void setHorizontalAlignment(int halign) Setzen der horizontalen Ausrichtung gemäß halign (für Text und Bild)
public void setVerticalAlignment(int valign) Setzen der vertikalen Ausrichtung gemäß valign (für Text und Bild)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 565 – 00 – TH – 03 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (5) •••• Die Klasse JButton (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von einfachen Schaltknöpfen (Schaltflächen).
◇ Auch JButton-Objekte können – im Unterschied zu den AWT-Button-Objekten – sowohl Text als auch ein Bild (auch beides kombiniert) darstellen.
◇ Auch bei JButton-Objekten kann die Ausrichtung sowohl des Textes als auch des Bildes innerhalb ihres Darstel- lungsbereichs festgelegt werden. Default-Ausrichtung für Text und Bilder : horizontal rechtsbündig, vertikal zentriert Explizite Festlegung der Ausrichtung : SwingConstants.CENTER (zentriert) SwingConstants.RIGHT (rechtsbündig) SwingConstants.LEFT (linksbündig) SwingConstants.TOP (obenbündig) SwingConstants.BOTTOM (untenbündig)
◇ Im Unterschied zu JLabel-Objekten können JButton-Objekte (Schaltknöpfe !) vom Benutzer veranlasste Ereig- nisse auslösen. Ein Schaltknopf kann auch den Focus besitzen und dann auch Tastatur-Eingaben empfangen. Ein Schaltknopf kann vom Benutzer – z.B. durch einen Mausklick oder bei vorhandenen Focus durch die Leertaste – betätigt ("gedrückt") werden. Ein "gedrückter" Schaltknopf ändert seine Hintergrundfarbe.
◇ Konstruktoren (Auswahl)
◇ Der überwiegende Teil der von der Klasse JButton angebotenen Schnittstelle ist geerbt von der Klasse AbstractButton.
Teilweise werden die gleichen Memberfunktionen – mit gleicher Funktionalität – wie bei der Klasse JLabel zur Verfügung gestellt Memberfunktionen (von AbstractButton geerbt, Auswahl)
public JButton() Erzeugung eines JButton-Objekts ohne "Inhalt"
public JButton(String text) Erzeugung eines JButton-Objekts das mit dem Text text beschriftet ist (horizontal rechtsbündig ausgerichtet)
public JButton(Icon image) Erzeugung eines JButton-Objekts, das mit dem Bild image versehen ist (horizontal rechtsbündig ausgerichtet)
public JButton(String text, Icon image) Erzeugung eines JButton-Objektsd, das mit dem Text text beschriftet und mit dem Bild image versehen ist
public String getText() Rückgabe des dargestellten Textes
public Icon getIcon() Rückgabe des dargestellten Bildes
public void setText(String text) Setzen des darzustellenden Textes auf text
public void setIcon(Icon image) Setzen des darzustellenden Bildes auf image
public void setHorizontalAlignment(int halign) Setzen der horizontalen Ausrichtung gemäß halign (für Text und Bild)
public void setVerticalAlignment(int valign) Setzen der vertikalen Ausrichtung gemäß valign (für Text und Bild)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 566 – 00 – TH – 05 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (6) •••• Die Klasse JTextField (Package javax.swing)
◇ Diese Klasse ist von der abstrakten Basisklasse JTextComponent (Package javax.swing.text) abgeleitet. Sie dient zur Erzeugung von editierbaren einzeiligen Textfeldern. Die Editierbarkeit kann ein- und ausgeschaltet werden (Default nach Objekt-Erzeugung : eingeschaltet).
◇ JTextField-Objekte können sowohl zur Ausgabe als auch zur Eingabe (wenn die Editierbarkeit eingeschaltet ist) von Text verwendet werden.
◇ Die Größe eines Textfeldes (= Anzahl der dargestellten Zeichenpositionen) kann kleiner (und natürlich auch größer) als die Textlänge sein. Das heisst, dass auch Text eingegeben werden kann, desen Länge die Anzahl der darstellbaren Positionen überschreitet.
◇ Die horizontale Ausrichtung des Textes innerhalb des dargestellten Zeilenfensters kann festgelegt werden. Hierfür stehen die folgenden Konstanten zur Verfügung : - JTextField.LEFT (linksbündig) - JTextField.RIGHT (rechtsbündig) - JTextField.CENTER (zentriert) - JTextField.LEADING (Darstellung der führenden Zeichen, wenn Feldlänge kleiner als Textlänge, default) - JTextField.TRAILING (Darstellung der Zeichen am Ende, wenn Feldlänge kleiner als Textlänge)
◇ Die Editierfunktionalität umfasst auch die Zusammenarbeit mit dem Clipboard : Text kann aus dem Clipboard einge- fügt bzw im Textfeld markiert und – ausgeschnitten oder kopiert – in das Clipboard eingefügt werden.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl) Die meisten der nachfolgend aufgeführten Memberfunktionen sind von der Klasse JTextComponent geerbt. *) geerbt von JTextComponent (Package javax.swing.text)
public JTextField() Erzeugung eines "leeren" JTextField-Objekts, die Feldgröße = 0
public JTextField(String text) Erzeugung eines JTextField-Objekts, das mit text initialisiert ist, die Feldgröße wird durch die Länge von text bestimmt.
public JTextField(int cols) Erzeugung eines "leeren" JTextField-Objekts, die Feldgröße ist durch cols festgelegt.
public JTextField(String text, Erzeugung eines JTextField-Objekts, das mit text initialisiert ist, int cols) die Feldgröße ist durch cols festgelegt
public void setColumns(int cols) Setzen der Feldgröße auf cols, das Layout wird ungültig gesetzt
public String getText() *) Rückgabe des im Textfeld enthaltenen Textes
public String getSelectedText() *) Rückgabe des markierten Teils des im Textfeld enthaltenen Textes
public void setText(String text) *) Setzen des im Textfeld enthaltenen Textes auf text
public void setEditable(boolean b) Setzen / Aufheben der Editierbarkeit des Textfeldes gemäß b *) b==true : Setzen der Editierbarkeit, andernfalls Aufheben
public boolean isEditable() *) Ermittelung der Editierbarkeit des Textfeldes Rückgabewert ==true : editierbar, andernfalls nicht editierbar
public void setHorizontalAlignment(int halign) Setzen der horizontalen Ausrichtung des Textfeldes auf halign
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 567 – 01 – TH – 02 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-1) •••• Die Klasse JTextArea (Package javax.swing)
◇ Diese Klasse ist ebenfalls von der Klasse JTextComponent abgeleitet. Sie dient zur Darstellung editierbarer mehrzeiliger Textfelder. Wie bei der Klasse JTextField kann die Editierbarkeit ein- und ausgeschaltet werden (Default nach Objekt- Erzeugung : eingeschaltet).
◇ JTextArea-Objekte können sowohl zur Ausgabe als auch zur Eingabe (bei eingeschalteter Editierbarkeit) von Text, der mehrere Zeilen umfassen kann, eingesetzt werden. Die Größe des im JTextArea-Objektes darzustellenden Textes kann sich damit dynamisch ändern.
◇ Auch bei dieser Klasse schliesst die Editierfunktionalität die Verwendung des Clipboards ein : Text kann aus dem Clip- board eingefügt bzw im Textfeld markiert und – ausgeschnitten oder kopiert – in das Clipboard eingefügt werden.
◇ Die Klasse JTextArea stellt mehrere Methoden zur Verfügung, mit denen der dargestellte Text auch vom Programm aus editiert werden kann. U.a. existieren Methoden zum zeilenweisen Text-Zugriff sowie zum Einfügen und Anhängen von Text.
◇ Die Größe des im JTextArea-Objektes darzustellenden Textes kann sich infolge des benutzer-initiierten oder pro- gramm-initiierten Editierens dynamisch ändern.
◇ Es ist möglich, für ein JTextArea-Objekt die Anzahl der Zeilen und Spalten festzulegen. Diese dienen zur Ermitt- lung seiner bevorzugten Größe (preferred size), die aber nicht der Größe des tatsächlich dargestellten Textfensters (Darstellungsbereich) entsprechen muß. Diese wird vielmehr durch den eingesetzten Layout-Manager gegebenenfalls unter Berücksichtigung der Größe des umfassenden Containers festgelegt.
◇ Für den Fall, dass eine darzustellende Zeile länger als die dargestellte Textfenster-Breite ist, kann ein automatischer Zeilenumbruch eingeschaltet werden Bei eingeschalteten Zeilenumbruch kann festgelegt werden, ob ein Umbruch nach jedem Zeichen (zeichenweiser Um- bruch) oder nur an einer Wortgrenze (wortweiser Umbruch) erfolgen kann. Defaultmässig ist der Zeilenumbruch ausgeschaltet. Der nicht in das dargestellte Fenster passende Zeilenteil ist dann nicht sichtbar. Analoges gilt, wenn die tatsächliche Anzahl der darzustellenden Textzeilen größer als die durch das dargestellte Text- fenster gegebene Zeilenzahl ist.
◇ JTextArea-Objekte besitzen keine Scroll-Fähigkeiten (Unterschied zu der AWT-Klasse TextArea). Diese lassen sich aber durch das Einbetten eines JTextArea-Objektes in ein JScrollPane-Objekt realisieren. In diesem Fall wird für den Scrollbereich die durch Zeilen- und Spaltenzahl festgelegte bevorzugte Größe berücksichtigt.
◇ Konstruktoren (Auswahl)
public JTextArea() Erzeugung eines "leeren" JTextArea-Objekts (Die Referenz auf den enthaltenen String ist null) Die Werte für die Anzahl der Zeilen und Spalten werden auf 0 gesetzt
public JTextArea(String text) Erzeugung eines JTextArea-Objekts, das mit text initialisiert ist, Die Werte für die Anzahl der Zeilen und Spalten werden auf 0 gesetzt
public JTextArea(int rows, Erzeugung eines "leeren" JTextArea-Objekts, int cols) Die Anzahl der Zeilen ist durch rows, die Anzahl der Spalten durch cols festgelegt.
public JTextArea(String text, Erzeugung eines JTextArea-Objekts, das mit text initialisiert ist, int rows, Die Anzahl der Zeilen ist durch rows, die Anzahl der Spalten durch int cols) cols festgelegt.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 567 – 02 – TH – 02 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-2) •••• Die Klasse JTextArea (Package javax.swing), Forts.
◇ Memberfunktionen (Auswahl) Wie in der Klasse JTextField werden zahlreiche Memberfunktionen von der Klasse JTextComponent geerbt. Zusätzlich definiert die Klasse JTextArea eine Reihe eigener Methoden *) geerbt von JTextComponent (Package javax.swing.text)
public String getText() *) Rückgabe des im Textfeld enthaltenen Textes
public String getSelectedText() *) Rückgabe des markierten Teils des im Textfeld enthaltenen Textes
public void setText(String text) *) Setzen des im Textfeld enthaltenen Textes auf text
public void setEditable(boolean b) Setzen / Aufheben der Editierbarkeit des Textfeldes gemäß b *) b==true : Setzen der Editierbarkeit, andernfalls Aufheben
public boolean isEditable() *) Ermittlung der Editierbarkeit des Textfeldes Rückgabewert ==true : editierbar, andernfalls nicht editierbar
public void setRows(int rows) Setzen der Anzahl Zeilen auf rows
public void setColumns(int cols) Setzen der Anzahl Spalten auf cols
public int getRows() Ermittlung der festgelegten Zeilen-Anzahl
public int getColumns() Ermittlung der festgelegten Spalten-Anzahl
public int getLineCount() Ermittlung der tatsächlich im Text vorhandenen Zeilenzahl
public void setLineWrap(boolean b) Setzen/Aufheben des automatischen Zeilenumbruchs gemäß b b==true : Setzen des Zeilenumbruchs, andernfalls Aufheben
public boolean getLineWrap() Ermittlung, ob automatischer Zeilenumbruch gesetzt ist Rückgabewert ==true : Zeilenumbruch ist gesetzt
public void setWrapStyleWord(boolean b) Setzen der Art des Zeilenumbruchs gemäß b b==true : wortweiser Zeilenumbruch b==false : zeichenweiser Zeilenumbruch (Default)
public boolean getWrapStyleWord() Ermittlung der Art des Zeilenumbruchs Rückgabewert ==true : wortweiser Zeilenumbruch Rückgabewert ==false : zeichenweiser Zeilenumbruch
void append(String str) Anhängen des Strings str an das Ende des dargestellten Textes
void insert(String str, int pos) Einfügen des Strings str an der Position pos im Text
void replaceRange(String str, Ersetzen des Textes zwischen den Positionen beg und end int beg, int end) durch den String str
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 567 – 03 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-3) •••• Demonstrationsprogramm zur Klasse JTextArea (JTextAreaDemo)
// JTextAreaDemo.java import java.awt.*; import javax.swing.*; import java.io.*; public class JTextAreaDemo extends JFrame { private final static String DEF_FILE_NAME = "schlechterwitz.txt"; private Container c; private JTextField tf; private JTextArea ta; public JTextAreaDemo(String dname) { super("JTextAreaDemo"); tf = new JTextField("Inhalt der Datei \"" + dname + '\"'); tf.setHorizontalAlignment(JTextField.CENTER); tf.setFont(new Font("SansSerif", Font.BOLD, 14)); tf.setBackground(Color.YELLOW); c=getContentPane(); ta = new JTextArea(20, 50); if (dname!=null) fillTextAreaFromFile(dname); ta.setFont(new Font("SansSerif", Font.PLAIN, 13)); //ta.setLineWrap(true); // Setzen des automatischen Zeilenumbruchs //ta.setWrapStyleWord(true); // Setzen der Umbruchsart auf wortweise c.add(tf, BorderLayout.NORTH); c.add(ta); setSize(360, 270); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } private void fillTextAreaFromFile(String dname) { try { BufferedReader bfr = new BufferedReader(new FileReader(dname)); String line; while ((line=bfr.readLine()) != null) ta.append(line + '\n'); bfr.close(); } catch(IOException ex) { System.out.println("Exception " + ex.getMessage()); } } public static void main(String[] args) { String fname; if (args.length==0) fname = DEF_FILE_NAME; else fname = args[0]; new JTextAreaDemo(fname).setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 567 – 04 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-4) •••• Ausgabe des Demonstrationsprogramms zur Klasse JTextArea (JTextAreaDemo)
◇ Automatischer Zeilenumbruch nicht gesetzt (default)
◇ Automatischer Zeilenumbruch gesetzt (zeichenweiser Umbruch)
◇ Automatischer Zeilenumbruch gesetzt (wortweiser Umbruch)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 568 – 01 – TH – 03 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-1) •••• Die Klasse JScrollPane (Package javax.swing)
◇ Objekte dieser Klasse dienen zur Einbettung anderer GUI-Komponenten in einen scrollbaren Darstellungsbereich. Statt die GUI-Komponente direkt in einen Container einzufügen, wird sie in ein JScrollPane-Objekt eingebettet und dieses dann in den Container eingefügt.
◇ JScrollPane-Objekte verwalten einen Darstellungsbereich (viewport), in dem die eingebettete GUI-Komponente eingeblendet wird. Wenn die eingebettete Komponente größer als der zur Verfügung stehende Darstellungsbereich ist, wird sie nur aus- schnittsweise angezeigt. Mit Hilfe von zwei Schiebereglern (scroll bars, horizontale und vertikale Bildlaufleiste) kann der dargestellte Ausschnitt dynamisch verändert werden.
◇ Es kann festgelegt werden, wann die Bildlaufleisten sichtbar sein sollen (Scroll Bar Policy) :
▻ nur sichtbar, wenn nötig (default)
▻ immer sichtbar
▻ nie sichtbar Dies kann – getrennt für die vertikale und horizontale Bildlaufleiste – im Konstruktor bei der JScrollPane-Objekt- Erzeugung oder später mittels spezieller Memberfunktionen erfolgen. Zur Festlegung stehen die folgenden – im implementierten Interface ScrollPaneConstants (Package javax.swing) definierten – Konstanten zur Verfügung : - JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED (vertikale Bildlaufleiste nur bei Bedarf sichtbar) - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED (horizontale Bildlaufleiste nur bei Bedarf sichtbar) - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS (vertikale Bildlaufleiste immer sichtbar) - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS (horizontale Bildlaufleiste immer sichtbar) - JScrollPane.VERTICAL_SCROLLBAR_NEVER (vertikale Bildlaufleiste nie sichtbar) - JScrollPane.HORIZONTAL_SCROLLBAR_NEVER (horizontale Bildlaufleiste nie sichtbar)
◇ Prinzipiell kann jede beliebige GUI-Komponente in ein JScrollPane-Objekt eingebettet werden. Diese kann im Konstruktor angegeben oder mittels einer entsprechenden Memberfunktion festgelegt werden.
◇ Für ein JScrollPane-Objekt können zusätzlich ein Zeilen-Header, ein Spalten-Header und Eck-Komponenten festgelegt werden.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl)
public JScrollPane() Erzeugung eines "leeren" JScrollPane-Objekts. Beide Bildlaufleisten werden nur bei Bedarf dargestellt
public JScrollPane(Component view) Erzeugung eines JScrollPane-Objekts, in dem das GUI- Komponenten-Objekt view eingebettet ist. Beide Bildlaufleisten werden nur bei Bedarf dargestellt
public JScrollPane(Component view, Erzeugung eines JScrollPane-Objekts, in dem das GUI- int vsbPol, int hsbPol) Komponenten-Objekt view eingebettet ist Die Sichtbarkeit der Bildlaufleisten wird durch vsbPol (verti- kal und hsbPol (horizontal) festgelegt
public void setVerticalScrollBarPolicy(int pol) Setzen der ScrollBarPolicy für die vertikale Bildlaufleiste auf pol
public void setHorizontalScrollBarPolicy(int pol) Setzen der ScrollBarPolicy für die horizontale Bildlaufleiste auf pol
public void setViewportView(Component view) Einbettung des GUI-Komponenten-Objekts view
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 568 – 02 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-2) •••• Demonstrationsprogramm zur Klasse JScrollPane (JScrollPaneDemo)
// JScrollPaneDemo.java // Einbettung eines JTextArea-Objekts in ein JScrollPane-Objekt // Modifikation des Demonstrations-Programms zur Klasse JTextArea import java.awt.*; import javax.swing.*; import java.io.*; public class JScrollPaneDemo extends JFrame { final static String DEF_FILE_NAME = /*"beispiel.txt"*/"schlechterwitz.txt"; private Container c; private JTextField tf; private JTextArea ta; private JScrollPane sp; public JScrollPaneDemo(String dname) { super("JScrollPaneDemo"); tf = new JTextField("Inhalt der Datei \"" + dname + '\"'); tf.setHorizontalAlignment(JTextField.CENTER); tf.setFont(new Font("SansSerif", Font.BOLD, 14)); tf.setBackground(Color.YELLOW); c=getContentPane(); ta = new JTextArea(20,50); if (dname!=null) fillTextAreaFromFile(dname); ta.setFont(new Font("SansSerif", Font.PLAIN, 13)); sp = new JScrollPane(ta); c.add(tf, BorderLayout.NORTH); c.add(sp); setSize(380, 250); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } private void fillTextAreaFromFile(String dname) { try { BufferedReader bfr = new BufferedReader(new FileReader(dname)); String line; while ((line=bfr.readLine()) != null) ta.append(line + '\n'); bfr.close(); } catch(IOException ex) { System.out.println("Exception " + ex.getMessage()); } } public static void main(String[] args) { String fname; if (args.length==0) fname = DEF_FILE_NAME; else fname = args[0]; new JScrollPaneDemo(fname).setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 568 – 03 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-3) •••• Ausgabe des Demonstrationsprogramms zur Klasse JScrollPane (JScrollPaneDemo)
◇ Automatischer Zeilenumbruch für das eingebettete JTextArea-Objekt nicht gesetzt (default)
◇ Automatischer Zeilenumbruch für das eingebettete JTextArea-Objekt gesetzt (wortweiser Umbruch)
◇ Automatischer Zeilenumbruch für das eingebettete JTextArea-Objekt nicht gesetzt (default)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 568 – 04 – TH – 02 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-4) •••• Weiteres Demonstrationsprogramm zur Klasse JScrollPane (JScrollPaneDemo2)
// JScrollPaneDemo2.java // Einbettung eines JButton-Objekts mit einem Bild in ein JScrollPane-Objekt import java.awt.*; import javax.swing.*; import java.io.*; public class JScrollPaneDemo2 extends JFrame { final static String DEF_FILE_NAME = "UnixCountry.jpg"; private Container c; private JButton but; // alternativ : JLabel but; private JTextField tf; private JScrollPane sp; public JScrollPaneDemo2(String dname) { super("JScrollPaneDemo2"); tf = new JTextField("Inhalt der Datei \"" + dname + '\"'); tf.setHorizontalAlignment(JTextField.CENTER); tf.setFont(new Font("SansSerif", Font.BOLD, 14)); tf.setBackground(Color.YELLOW); c=getContentPane(); Icon pict = new ImageIcon(dname); but = new JButton(pict); // alternativ : but = new JLabel(pict); sp = new JScrollPane(but); c.add(tf, BorderLayout.NORTH); c.add(sp); setSize(550, 350); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { String fname; if (args.length==0) fname = DEF_FILE_NAME; else fname = args[0]; new JScrollPaneDemo2(fname).setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 568 – 05 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-5) •••• Ausgabe des weiteren Demonstrationsprogramms zur Klasse JScrollPane (JScrollPaneDemo2)
◇ verschiedene Stellungen der Schieberegler (Bildlaufleiste)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 569 – 00 – TH – 02 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (9) •••• Die Klasse JCheckBox (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von Auswahlfeldern. Ein Auswahlfeld (check box) ist ein kleines Kästchen, das bei der Anwahl selektiert und deselektiert werden kann. Der jeweilige Selektionszustand wird angezeigt : De-selektiert ist das Kästchen leer, selektiert enthält es einen kleinen Haken.
◇ Ein JCheckBox-Objekt dient i.a. zur Darstellung eines logischen Wertes (boolean) auf einer GUI-Oberfläche.
◇ In einer Gruppe von JCheckBox-Objekten (Auswahlfeldern) können beliebig viele selektiert sein
◇ Ein JCheckBox-Objekt kann mit einem Text beschriftet oder/und mit einem Bild versehen werden. Ein Bild ersetzt dabei das Auswahlfeld-Kästchen in der Darstellung. Eine eventuelle Selektion kann dann optisch nicht mehr erkannt werden.
◇ Die Klasse ist von der Klasse JToggleButton abgeleitet, die ihrerseits die abstrakte Klasse AbstractButton als direkte Basisklasse hat.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen : Ein großer Teil der angebotenen Schnittstelle ist von der Klasse AbstractButton geerbt, u.a. :
public JCheckBox() Erzeugung eines nicht selektierten JCheckBox-Objekts ohne Text und ohne Bild
public JCheckBox(String text) Erzeugung eines nicht selektierten JCheckBox-Objekts, mit dem Text text beschriftet
public JCheckBox(String text, Erzeugung eines JCheckBox-Objekts, dessen Anfangs- boolean select) Selektionszustand durch select festgelegt ist (select==true : selektiert), Beschriftung mit Text text
public JCheckBox(Icon image) Erzeugung eines nicht selektierten JCheckBox-Objekts, mit dem Bild image versehen
public JCheckBox(Icon image, Erzeugung eines JCheckBox-Objekts, dessen Anfangs- boolean select) Selektionszustand durch select festgelegt ist (select==true : selektiert), mit dem Bild image versehen
public JCheckBox(String text, Erzeugung eines nicht selektierten JCheckBox-Objekts, Icon image) mit dem Text text beschriftet und dem Bild image versehen
public JCheckBox(String text, Erzeugung eines JCheckBox-Objekts, dessen Anfangs- Icon image, Selektionszustand durch select festgelegt ist boolean select) (select==true : selektiert), mit dem Text text beschriftet und mit dem Bild image versehen
public void setSelected(boolean b) Setzen des Selektionszustands gemäß b b==true : selektiert, andernfalls nicht selektiert
public boolean isSelected() Ermittlung des Selektionszustands Rückgabewert ==true : selektiert, ==false : nicht selektiert
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 56A – 01 – TH – 04 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (10-1) •••• Die Klasse JRadioButton (Package javax.swing)
◇ Diese Klasse dient ebenfalls zur Erzeugung von Auswahlfeldern. JRadioButton-Objekte können somit auch zur Darstellung logischer Werte (boolean) auf einer GUI-Oberfläche eingesetzt werden.
◇ Im Unterschied zur Klasse JCheckBox werden aber mehrere JRadioButton-Objekte meist so zu einer Gruppe zusammengefasst, dass immer nur ein Auswahlfeld aus der Gruppe selektiert werden soll (und kann) (Gruppe alter- nativer Auswahlfelder).
◇ Ein Auswahlfeld der Klasse JRadioButton wird durch einen kleinen Kreis dargestellt. Im unselektierten Zustand ist der Kreis leer, bei Selektion erscheint ein Punkt im Kreis.
◇ Die Klasse JRadioButton ist ebenfalls von der Klasse JToggleButton und damit auch von der abstrakten Klasse AbstractButton abgeleitet.
◇ Auch ein JRadioButton-Objekt kann mit einem Text beschriftet oder/und mit einem Bild versehen werden. Ein Bild ersetzt dabei den Auswahlfeld-Kreis in der Darstellung. Eine eventuelle Selektion kann dann optisch nicht mehr erkannt werden.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen : Die angebotene Schnittstelle entspricht weitgehend – soweit sie von der Klasse AbstractButton geerbt ist – der Schnittstelle der Klasse JCheckBox. U.a. stehen somit auch die folgenden Methoden zur Verfügung :
public JRadioButton() Erzeugung eines nicht selektierten JRadioButton-Objekts ohne Text und ohne Bild
public JRadioButton (String text) Erzeugung eines nicht selektierten JRadioButton -Objekts, mit dem Text text beschriftet
public JRadioButton (String text, Erzeugung eines JRadioButton -Objekts, dessen Anfangs- boolean select) Selektionszustand durch select festgelegt ist (select==true : selektiert), Beschriftung mit Text text
public JRadioButton (Icon image) Erzeugung eines nicht selektierten JRadioButton -Objekts, mit dem Bild image versehen
public JRadioButton (Icon image, Erzeugung eines JRadioButton -Objekts, dessen Anfangs- boolean select) Selektionszustand durch select festgelegt ist (select==true : selektiert), mit dem Bild image versehen
public JRadioButton (String text, Erzeugung eines nicht selektierten JRadioButton -Objekts, Icon image) mit dem Text text beschriftet und dem Bild image versehen
public JRadioButton (String text, Erzeugung eines JRadioButton -Objekts, dessen Anfangs- Icon image, Selektionszustand durch select festgelegt ist boolean select) (select==true : selektiert), mit dem Text text beschriftet und mit dem Bild image versehen
public void setSelected(boolean b) Setzen des Selektionszustands gemäß b b==true : selektiert, andernfalls nicht selektiert
public boolean isSelected() Ermittlung des Selektionszustands Rückgabewert ==true : selektiert, ==false : nicht selektiert
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 56A – 02 – TH – 03 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (10-2) •••• Die Klasse ButtonGroup (Package javax.swing)
◇ Objekte dieser Klasse dienen zur logischen Zusammenfassung mehrerer JRadioButton-Objekte zu einer Gruppe, in der immer nur ein Objekt selektiert werden kann.
◇ Sie stellen selbst keine GUI-Komponenten dar und erscheinen deshalb auch nicht auf der GUI-Oberfläche.
◇ Nach der Erzeugung eines ButtonGroup-Objekts und dem Hinzufügen der JRadioButton-Objekte, die zusam- mengefasst werden sollen, sind alle JRadioButton-Objekte zunächst de-selektiert. Nach der erstmaligen Selektion eines JRadioButton-Objekts ist immer genau ein Objekt der Gruppe selektiert. Es gibt danach keine Möglichkeit mehr, alle Objekte gleichzeitig in den de-selektierten Zustand zu versetzen.
◇ Konstruktor :
◇ Memberfunktionen :
◇ Anmerkung :
▻ Genaugenommen können durch ein ButtonGroup-Objekt nicht nur JRadioButton-Objekte sondern Objekte jeder von AbstractButton abgeleiteten Klasse zusammengefasst werden (Parameter von add() !!!). Allerdings ist eine derartige Zusammenfassung nicht immer sinnvoll.
▻ Beispielsweise lassen sich auch JCheckBox-Objekte derartig zu einer Gruppe zusammenfassen. Diese Gruppe ver hält sich dann wie eine JRadioButton-Gruppe (nur eine Checkbox kann jeweils alternativ selektiert werden), was aber der typischen Anwendung von JCheckBox-Objekten wiederspricht.
▻ Bei Objekten einiger von AbstractButton abgeleiteten Klassen (z.B. JButton und JMenuItem) macht die Zusammenfassung zu einer Gruppe schon deshalb keinen Sinn, weil sie den jeweiligen Selektionszustand nicht anzeigen.
public ButtonGroup() Erzeugung eine neuen ButtonGroup-Objekts
public void add(AbstractButton b) Hinzufügen des Buttons (konkret JRadioButton-Objekts) b zur Gruppe
public void remove(AbstractButton b) Entfernen des Buttons (konkret JRadioButton-Objekts) b aus der Gruppe
public int getButtonCount() Rückgabe der Anzahl in der Gruppe enthaltenen AbstractButton-(konkret JRadioButton-)Objekte
public Enumeration<AbstractButton> Rückgabe aller in der Gruppe enthaltenen AbstractButton- getElements() (konkret JRadioButton-)Objekte
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 56A – 03 – TH – 01 -----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (10-3)
•••• Demonstrationsprogramm zu den Klassen JCheckBox und JRadioButton
// AuswahlfeldDemo.java import java.awt.*; import javax.swing.*; public class AuswahlfeldDemo extends JFrame { private Container c; private JCheckBox[] cba; private JRadioButton[] rba; public AuswahlfeldDemo(int anz) { setTitle("AuswahlfeldDemo"); c = getContentPane(); c.setLayout(new GridLayout(2,0)); cba = new JCheckBox[anz]; for (int i=0; i<cba.length; i++) { cba[i] = new JCheckBox("Auswahl " + (i+1)); c.add(cba[i]); } rba = new JRadioButton[anz]; ButtonGroup bg = new ButtonGroup(); for (int i=0; i<rba.length; i++) { rba[i] = new JRadioButton("Select " + (i+1)); bg.add(rba[i]); c.add(rba[i]); } setSize(380, 120); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { new AuswahlfeldDemo(4).setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 56B – 01 – TH – 05 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (11-1) •••• Die Klasse JPanel (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von Gruppierungsfeldern. Ein Gruppierungsfeld ist ein "innerer" Container, der in erster Linie zur strukturierten Gestaltung des Inhalts von Fensterbereichen dient. Mit einem Gruppierungsfeld lassen sich mehrere Komponenten zu einer Komponente zusammenfassen, die dann wie- derum in einen anderen Container (Top-Level-Container oder ein weiterer "innerer" Container) eingefügt werden kann.
◇ Die Klasse JPanel ist von der Klasse JComponent abgeleitet.
◇ Wie andere Container auch, verwenden JPanel-Objekte einen Layout-Manager. Im Unterschied zu den Top-Level- Containern ist bei ihnen Flow-Layout als Default eingestellt. Ein anderes Layout lässt sich gegebenenfalls bei der Objekt-Erzeugung im Konstruktor oder mittels der – von der Klasse Container geerbten – Methode setLayout() setzen. Allerdings ist ein Setzen des BoxLayouts bei der Objekterzeugung ist nicht möglich. Die folgende Anweisung JPanel mpan = new JPanel(new BoxLayout(mpan, BoxLayout.Y_AXIS));
führt zur der Compiler-Fehlermeldung "Variable mpan ist nicht initialisiert worden".
◇ JPanel-Objekte verfügen von Haus aus über keine Umrandung. Bei Bedarf lassen sich aber Umrandungen mit der von der Klasse JComponent geerbten Methode setBorder() setzen.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen Die Klasse JPanel stellt die Methoden ihrer direkten und indirekten Basisklassen JComponent, Container und Component zur Verfügung. Sie fügt nur wenige weitere – für die Anwendung i.a. nicht wesentliche – Methoden hinzu.
public JPanel() Erzeugung eines JPanel-Objekts (Flow-Layout voreingestellt)
public JPanel(LayoutManager layout) Erzeugung eines JPanel-Objekts mit dem durch layout festgelegten Layout-Manager
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 56B – 02 – TH – 03 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (11-2) •••• Demonstrationsprogramm zur Klasse JPanel
import java.awt.*; import javax.swing.*; import javax.swing.border.*; public class JPanelDemo extends JFrame { Container c; JPanel pan1, pan2, pan3; public JPanelDemo() { super("JPanelDemo"); c=getContentPane(); pan1 = new JPanel(); pan2 = new JPanel(); pan3 = new JPanel(new GridLayout(2,3)); for (int i=1; i<=4; i++) pan1.add(new JButton("Button " + i)); pan1.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); pan1.setBackground(Color.ORANGE); Icon javaLogo = new ImageIcon("javalogo52x88.gif"); JLabel lab1 = new JLabel(javaLogo); JLabel lab2 = new JLabel("Java", SwingConstants.LEFT); lab2.setBorder(BorderFactory.createEmptyBorder(0,0,0,30)); JLabel lab3 = new JLabel("avaJ", SwingConstants.RIGHT); lab3.setBorder(BorderFactory.createEmptyBorder(0,30,0,0)); pan2.add(lab2); pan2.add(lab1); pan2.add(lab3); for (int i=1; i<=6; i++) pan3.add(new JCheckBox("Auswahl " + i)); Border bord1 = BorderFactory.createLineBorder(Color.GREEN, 5); Border bord2 = BorderFactory.createTitledBorder(bord1, "Auswahl"); pan3.setBorder(bord2); c.add(pan1, BorderLayout.NORTH); c.add(pan2, BorderLayout.CENTER); c.add(pan3, BorderLayout.SOUTH); setSize(380, 270); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { new JPanelDemo().setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 56C – 01 – TH – 01 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (12-1) •••• Die Klasse Box (Package javax.swing)
◇ Diese – direkt von JComponent abgeleitete – Klasse ist eine weitere "innere" Container-Klasse. Sie dient eben- falls zur Erzeugung von Gruppierungsfeldern.
◇ Defaultmässig ist Box-Layout eingestellt. Dieses Layout kann jedoch nicht verändert werden Die – indirekt von Container geerbte – Methode setLayout(...) ist so überschrieben, dass sie immer eine AWTError-Exception wirft. � Gruppierungs-Box.
◇ Die Anordnungs-Achse des verwendeten Box-Layouts (vertikal oder horizontal) ist bei der Objekt-Erzeugung anzugeben.
◇ Bezüglich der Verwendung als Gruppierungsfelder können Box-Objekte im wesentlichen wie JPanel-Objekte eingesetzt werden. Auch Box-Objekte verfügen von Haus aus über keine Umrandung. Mittels der von JComponent geerbten Methode setBorder(...) lassen sich jederzeit gewünschte Umrandungen setzen.
◇ Als zusätzliche Besonderheit stellt die Klasse Box eine Reihe von statischen Methoden zur Verfügung, mit denen unsichtbare GUI-Komponenten erzeugt werden können, die sich als Abstands- und Füll-Komponenten im Box- Layout – auch in Nicht-Box-Containern – einsetzen lassen. Diese Komponenten sind Objekte der Klasse Box.Filler (innere Klasse von Box), die ebenfalls direkt von der Klasse JComponent abgeleitet ist. Prinzipiell können diese Komponenten auch in anderen Layouts verwendet werden, aber ihre wesentliche Bedeutung haben sie beim BoxLayout.
◇ Konstruktor
◇ Statische Methoden zur Objekterzeugung
◇ Statische Methoden zur Erzeugung unsichtbarer GUI-Komponenten (Auswahl)
public Box(int axis) Erzeugung eines Box-Objekts dessen Layout, die durch axis festgelegte Anordnungs-Achse besitzt. Folgende Konstante sind zulässige Werte für axis : - BoxLayout.X_AXIS (horizontale Anordnung, in einer Zeile) - BoxLayout.Y_AXIS (vertikale Anordnung, in einer Spalte) - BoxLayout.LINE_AXIS (für europäische Sprachen : horizontale Anordnung) - BoxLayout.PAGE_AXIS (für europäische Sprachen : vertikale Anordnung)
public static Box createHorizontalBox() Erzeugung eines Box-Objekts mit horizontaler Anordnungs-Achse seines Layouts public static Box createVerticalBox() Erzeugung eines Box-Objekts mit vertikaler Anordnungs-Achse seines Layouts
public static Component createRigidArea(Dimension d) Erzeugung eines Box.Filler-Objekts das die durch d definierte feste Grösse besitzt (� Abstands-Komponente) public static Component createHorizontalGlue() Erzeugung eines Box.Filler-Objekts variabler anpassbarer Breite (� horizontale Füll-Komponente)
public static Component createVerticalGlue() Erzeugung eines Box.Filler-Objekts variabler anpassbarer Höhe (� vertikale Füll-Komponente)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 56C – 03 – TH – 01 ------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (12-3) •••• Demonstrationsprogramm zur Klasse Box (und zu unsichtbaren GUI-Komponenten)
import javax.swing.*; import javax.swing.border.*; import java.awt.*; public class BoxDemo extends JFrame { public BoxDemo() { super("BoxDemo"); Box mbox = new Box(BoxLayout.Y_AXIS); Box box1 = Box.createHorizontalBox(); // = new Box(BoxLayout.X_AXIS); Box box2 = Box.createVerticalBox(); // = new Box(BoxLayout.Y_AXIS); mbox.setBorder(BorderFactory.createLineBorder(Color.BLACK,3)); box1.setBorder(BorderFactory.createLineBorder(Color.GREEN,3)); box2.setBorder(BorderFactory.createLineBorder(Color.RED,3)); box1.setAlignmentX(CENTER_ALIGNMENT); box2.setAlignmentX(CENTER_ALIGNMENT); for (int i=1; i<=3; i++) { box1.add(Box.createRigidArea(new Dimension(5,0))); box1.add(new JButton("HB-Button " + i)); } box1.add(Box.createHorizontalGlue()); box1.setMinimumSize(new Dimension(400, 60)); box1.setMaximumSize(box1.getMinimumSize()); box1.setPreferredSize(box1.getMinimumSize()); box2.add(Box.createVerticalGlue()); for (int i=1; i<=2; i++) { box2.add(new JButton("VB-Button " + i)); box2.add(Box.createRigidArea(new Dimension(0,5))); } mbox.add(Box.createRigidArea(new Dimension(0,10))); mbox.add(box1); mbox.add(Box.createRigidArea(new Dimension(0,10))); mbox.add(box2); mbox.add(Box.createRigidArea(new Dimension(0,10))); add(mbox, BorderLayout.CENTER); setSize(480, 300); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { new BoxDemo().setVisible(true); } }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 571 – 00 – TH – 03 ------------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (1)
•••• Delegation Event Model
◇ In Programmen mit einem grafischen Benutzerinterface findet die Kommunikation zwischen dem Benutzer und dem Programm mittels Ereignissen (events) statt.
◇ Benutzerinteraktionen mit der graphischen Oberfläche (wie z.B. Anwählen eines Schaltknopfes oder Auswahl eines Menue-Eintrags mittels Maus oder Tastatur, Schliessen eines Fensters, sonstige Mausbewegungen und Mausklicks, sonstige Tastatureingaben usw) lösen Ereignisse aus, die als Nachrichten vom Betriebssystem an das Programm gesandt werden. Auch Änderungen der Größe, der Lage, des Inhalts und des sonstigen Zustands von GUI-Komponenten können zu Ereig- nissen in diesem Sinne führen. Ereignisse können also von unterschiedlichem Typ sein.
◇ Innerhalb eines Java-Programms werden die durch Nachrichten angezeigten Ereignisse als Objekte spezieller Ereignis- Klassen (event objects) dargestellt. Diese Ereignis-Objekte kapseln Informationen über das jeweilige Ereignis (z.B. die Ereignisquelle, spezielle Para- meter, wie Mauskoordinaten, Tastatur-Codes usw)
◇ Die GUI-Komponente an der oder durch die ein Ereignis erzeugt wurde, wird als Ereignisquelle (event source) bezeichnet. Prinzipiell kann jede Komponente einer graphischen Oberfläche eine derartige Ereignisquelle sein.
◇ Zuständig für die Reaktion auf das Ereignis sind spezielle Ereignisempfänger, die sogenannten Event-Listener. Dies sind Objekte, die ein zum jeweiligen Ereignis passendes Bearbeitungs-Interface implementieren. Damit ein Event-Listener-Objekt die von einer bestimmten Ereignisquelle verursachten Ereignisse empfangen kann, muß es bei dieser Ereignisquelle als Listener registriert sein (Design Pattern Observer !). Dabei werden einem Listener nur die Ereignisse mitgeteilt, die zu seinem Typ passen, d.h. für die er ein passendes Bearbeitungs-Interface implementiert hat.
◇ Das Zustellen der einzelnen Ereignisse an die jeweils registrierten Event-Listener erfolgt durch den Aufruf der für den Ereignis-Typ zuständigen Bearbeitungsfunktion des Listeners (Call Back !). Dieser wird das Ereignis-Objekt als Para- meter übergeben. In jedem GUI-Programm ist hierfür ein eigener Thread zuständig, der event-dispatching thread.
◇ Zwischen einer Ereignisquelle und einem Event-Listener muß keine 1:1-Beziehung bestehen. Bei einer Ereignisquelle können durchaus mehrere Event-Listener registriert sein – sogar für den gleichen Ereignis-Typ. Das Ereignis wird dann allen bei der Quelle für den jeweiligen Ereignis-Typ registrierten Event-Listenern zugestellt. Andererseits kann ein Event-Listener auch gleichzeitig bei mehreren Ereignisquellen registriert sein.
◇ Das in Java seit dem JDK 1.1 implementierte Delegation Event Model wird sowohl für AWT-Komponenten als auch Swing-Komponenten angewendet.
◇ Es ermöglicht eine klare Trennung zwischen dem Programmcode zur Oberflächengestaltung (GUI-Klassen !) und dem Code zur Ereignisverarbeitung (Event-Listener-Klassen) als Schnittstelle zur Anwendungslogik.
Ereignisquelle 1 event Event-Listener 1
Ereignisquelle 2
Event-Listener 2
Event-Listener 3
event
Ereignisquelle 3
Event-Listener 4
event
event
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 572 – 00 – TH – 03 ------------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (2)
•••• Ereignis-Klassen
◇ Auszug aus der Hierarchie der Ereignisklassen
◇ Die verschiedenen Event-Klassen implementieren jeweils Memberfunktionen mit denen Informationen, die mit dem jeweiligen Event-Objekt verknüpft sind, ermittelt werden können.
◇ Die Klasse EventObject, Basisklasse aller Ereignis-Klassen, stellt die folgende Methode zur Verfügung :
Diese Methode wird von allen anderen Ereignis-Klassen geerbt und kann damit für alle Event-Objekte aufgerufen werden.
◇ Die verschiedenen Ereignis-Klassen sind jeweils bestimmten Ereignisse auslösenden Aktionen zugeordnet. Beispielsweise wird ein ActionEvent-Objekt durch folgende Aktionen erzeugt : - Betätigung eines Schaltknopfes - Selektierung eines Auswahlfeldes - Auswahl eines Menue- oder Auswahllisten-Eintrags - Betätigung der RET-Taste
◇ In vielen Fällen kann bei einer Komponente einer bestimmten GUI-Klasse ein Objekt einer bestimmten Ereignis-Klasse nur durch eine einzige Aktionsart erzeugt werden. Diese Aktionsart kann bei den verschiedenen GUI-Klassen durchaus unterschiedlich sein. Es gibt aber auch Ereignis-Klassen, die für mehrere verschiedene Aktionsarten bei der gleichen Komponente zuständig sind. Beispielsweise ist die Klasse MouseEvent sowohl für Mausbewegungen (mouse motion events) als auch für alle sonstigen Mausereignisse (mouse events, wie Knopfbetätigung, Maus-Eintritt, Maus-Austritt in Komponente) zuständig
EventObject (java.util)
AWTEvent (java.awt)
ChangeEvent (javax.swing.event)
ListSelectionEvent (javax.swing.event)
CaretEvent (javax.swing.event)
MenuEvent (javax.swing.event)
ComponentEvent (java.awt.event)
ActionEvent (java.awt.event)
ItemEvent (java.awt.event)
AncestorEvent (javax.swing.event)
InputEvent (java.awt.event)
ContainerEvent (java.awt.event)
WindowEvent (java.awt.event)
FocusEvent (java.awt.event)
KeyEvent (java.awt.event)
MouseEvent (java.awt.event)
. . . weitere Event- Klassen
. . . weitere Event- Klassen
. . . weitere Event- Klassen
AWT Swing
public Object getSource() Ermittlung der ursprünglichen Ereignisquelle
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 573 – 00 – TH – 02 -----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (3)
•••• Ereignis-Klassen, Forts.
◇ Da auf den verschiedenen GUI-Komponenten jeweils nur spezifische Aktionen ausgeführt werden können, können diese auch nur Ereignisse ganz bestimmter Klassen auslösen. Einige Ereignis-Klassen werden bereits in den Basisklassen der JFC-Hierarchie unterstützt. Entsprechende Ereignisse können daher in allen Komponenten der davon abgeleiteten Klassen ausgelöst werden. Einige GUI-Komponenten und die von ihnen unterstützen Ereignis-Klassen :
◇ Memberfunktionen (Auswahl) einiger Ereignis-Klassen zur Informationsermittlung über das Ereignis :
▻ Klasse AWTEvent
▻ Klasse ActionEvent
▻ Klasse ItemEvent
▻ Klasse WindowEvent
public int getID() Ermittlung der auslösenden Aktionsart (Klassenkonstante !)
public String getActionCommand() Ermittlung der für das Ereignis festgelegten Aktionskennung
public Object getItem() Ermittlung des vom Ereignis betroffenen Objekts
public int getStateChange() Ermittlung des geänderten Zustands (selektiert oder nicht selektiert)
public Window getWindow() Ermittlung des Fensters, das das Ereignis ausgelöst hat
GUI-Klasse unterstützte Ereignis-Klasse auslösende Aktionn Component ComponentEvent Position, Größe oder Sichtbarkeit wurden geändert FocusEvent Focus wurde erhalten oder verloren KeyEvent Tastatur wurde betätigt MouseEvent Maus wurde betätigt oder bewegt Container ContainerEvent Container-Inhalt wurde verändert Window WindowEvent Status des Fensters hat sich geändert JComponent AncestorEvent Umgebender Container hat sich verändert JButton ActionEvent Schaltknopf wurde betätigt ChangeEvent Zustand des Schaltknopfes hat sich geändert
JTextField ActionEvent RET-Taste wurde betätigt CaretEvent Cursorposition hat sich geändert JTextArea CaretEvent Cursorposition hat sich geändert JCheckBox ActionEvent Auswahlfeld wurde betätigt und ChangeEvent Zustand des Auswahlfelds hat sich geändert JRadioButton ItemEvent Selektionszustand hat sich geändert JComboBox ActionEvent Eintrag wurde ausgewählt oder editiert ItemEvent ausgewählter Eintrag hat sich geändert
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 574 – 00 – TH – 03 -----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (4)
•••• Listener-Interfaces
◇ Die beim Auftritt eines Ereignisses informierten Event-Listener müssen jeweils ereignisspezifisch reagieren können. Ein Ereignis einer bestimmten Klasse kann nur ein Listener empfangen, der bestimmte zur Ereignis-Klasse passende Reaktions-Methoden bereitstellt. � Jeder Listener muß ein bestimmtes Interface implementieren.
◇ Zu jeder Ereignis-Klasse ist mindestens ein passendes Listener-Interface definiert. Für einige Ereignis-Klassen gibt es auch mehrere Listener-Interfaces. Allgemein gilt : Zur Ereignis-Klasse AbcEvent existiert das Listener-Interface AbcListener. Beispiele : Ereignisklasse ActionEvent � Listener-Interface ActionListener Ereignisklasse ItemEvent � Listener-Interface ItemListener Bei mehreren mit einer Ereignis-Klasse korrespondierenden Listener-Interfaces gilt : Zur Ereignis-Klasse AbcEvent existieren Listener-Interfaces AbcXyzListener Beispiel : Ereignis-Klasse WindowEvent � Listener-Interface WindowListener WindowFocusListener WindowStateListener
◇ Die verschiedenen Interfaces sind definiert in den Packages java.awt.event und javax.swing.event.
◇ Alle Listener-Interfaces sind vom Interface EventListener (Package java.util) abgeleitet. Dieses deklariert keine Methoden sondern ist ein reines Marker-Interface.
◇ Einige Interfaces deklarieren genau eine Methode. Sie sind i.a. sogenannten semantischen Ereignissen zugeordnet. Andere Interfaces, die i.a. sogenannten Low-Level-Ereignissen zugeordnet sind, deklarieren mehrere Methoden. Eine Event-Listener-Klasse muß alle Methoden des Interfaces, das sie implementiert, definieren. Die jeweilige Methode enthält den vom Programm als Reaktion auf das Ereignis auszuführenden Code (� Event-Handler) Die Information eines Event-Listeners über ein eingetretenes Ereignis erfolgt durch den Aufruf einer dieser Methoden als Callback.
◇ Alle Methoden besitzen genau einen Parameter von der jeweiligen zugehörigen Ereignis-Klasse. Beim Aufruf einer Methode wird ihr das ausgelöste Ereignis-Objekt als aktueller Parameter übergeben.
◇ Einige Listener-Interfaces als Beispiele :
▻ Interface ActionListener (Package java.awt.event)
▻ Interface ItemListener (Package java.awt.event)
▻ Interface WindowListener (Package java.awt.event), unvollständig
public void actionPerformed(ActionEvent e) aufgerufen, wenn ein ActionEvent auftritt
public void itemStateChanged(ItemEvent e) aufgerufen, wenn ein ItemEvent auftritt
public void windowClosing(WindowEvent e) aufgerufen, wenn Fenster geschlossen werden soll
public void windowClosed(WindowEvent e) aufgerufen, wenn Fenster geschlossen wurde
public void windowActivated(WindowEvent e) aufgerufen, wenn Fenster aktiviert wurde
public void windowDeactivated(WindowEvent e) aufgerufen, wenn Fenster deaktiviert wurde
public void windowIconified(WindowEvent e) aufgerufen, wenn Fenster minimiert wurde
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 575 – 00 – TH – 04 -----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (5) •••• Listener-Adapter-Klassen
◇ Eine Klasse, die ein Listener-Interface implementiert, dass mehrere Methoden deklariert, muss sämtliche Metho- den definieren, auch wenn in der speziellen Anwendung nur eine von ihnen benötigt wird.
◇ Zur Vereinfachung der Definition von Listener-Klassen existieren für derartige Interfaces Adapter-Klassen. Es handelt sich bei Ihnen um abstrakte Klassen, die sämtliche Methoden des Interfaces mit leerer Funktionalität implementieren. Statt eine Listener-Klasse das jeweilige Listener-Interface direkt implementieren zu lassen, leitet man die Klasse von der zugehörigen Adapter-Klasse ab. Die Klasse muß dann lediglich die im konkreten Fall benötigte Methode über- schreiben.
◇ Wenn zum Listener-Interface AbcListener eine Adapter-Klasse existiert, lautet ihr Name AbcAdapter. Beispiel : Listener-Interface WindowListener � Listener-Adapter WindowAdapter •••• Listener-Klassen
◇ Sie müssen das Listener-Interface, das zu der Ereignis-Klasse, deren Objekte sie empfangen sollen, gehört, implemen- tieren. Eine Listener-Klasse kann auch mehrere Listener-Interfaces implementieren und damit auf Ereignisse unterschied- licher Klassen reagieren.
◇ Eine Listener-Klasse kann das oder die Listener-Interfaces
▻ entweder direkt implementieren
▻ oder von einer zugehörigen Adapter-Klasse abgeleitet werden.
◇ Zur programmtechnischen Realisierung eine Listener-Klasse existieren folgende Möglichkeiten :
▻ Realisierung der Listener-Klasse als innere Klasse
▻ Realisierung der Listener-Klasse als lokale Klasse oder anonyme Klasse
▻ Realisierung der Listener-Klasse als Top-Level-Klasse
▻ Verwendung der Container-Klasse als Listener-Klasse •••• Implementierung einer Ereignisverarbeitung im Anwender-Code
◆ Definition einer geeigneten Event-Listener-Klasse. In der (bzw den) zu implementierenden Interface-Methode(n) (Event-Handler) ist die Programmfunktionalität zu realisieren, die als Reaktion auf den Eintritt eines Ereignisses der betreffenden Art vorgesehen ist.
◆ Erzeugung eines Objekts dieser Event-Listener-Klasse (Event-Listener-Objekt).
◆ Registrierung des Event-Listener-Objekts bei der auf Ereignisse zu "überwachenden" GUI-Komponente. Hierfür stellen die GUI-Komponenten für die von ihnen unterstützten Listener-Typen entsprechende Registrierungs- funktionen zur Verfügung : Für EventListener vom Typ AbcListener � Funktion void addAbcListener(AbcListener lis) Beispiel : Klasse JButton für ActionListener-Objekte (geerbt von der Klasse AbstractButton) :
◆ Gegebenenfalls Festlegung von spezifischen Informationen, die einem Ereignis-Objekt übergeben werden. Beispiel : Klasse JButton : Setzen einer Aktionskennung (action command) für ActionListener-Objekte
(geerbt von der Klasse AbstractButton) :
public void addActionListener(ActionListener lis) Registrierung des Action-Listener-Objects lis
public void setActionCommand(String cmd) Setzen der Aktionskennung cmd
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 576 – 00 – TH – 02 -----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (6) •••• Demonstrationsprogramm zum Interface ActionListener
// ColorChangeDemo.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ColorChangeDemo extends JFrame { Container c; JButton but; public ColorChangeDemo() { super("ColorChangeDemo"); c=getContentPane(); c.setLayout(new FlowLayout()); but = new JButton("Change Backgroundcolor"); c.add(but); // ActionListener-Klasse als anonyme Klasse ActionListener actlis = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
float rwert = (float)Math.random();
float gwert = (float)Math.random();
float bwert = (float)Math.random();
c.setBackground(new Color(rwert, gwert, bwert));
}
};
but.addActionListener(actlis); setSize(300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { new ColorChangeDemo().setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 577 – 00 – TH – 01 -----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (6) •••• Demonstrationsprogramm zur Adapter-Klasse WindowAdapter
// WindowClosingDemo.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class WindowClosingDemo extends JFrame { Container c; JLabel lab; JCheckBox cb1, cb2; public WindowClosingDemo() { super("Window Closing Demo"); c = getContentPane(); c.setLayout(new FlowLayout()); lab = new JLabel("Zum Schliessen des Fensters bitte " + "beide Auswahlfelder selektieren"); lab.setBorder(BorderFactory.createEmptyBorder(10, 0, 25, 0)); cb1 = new JCheckBox("Auswahl 1"); cb2 = new JCheckBox("Auswahl 2"); c.add(lab); c.add(cb1); c.add(cb2); addWindowListener(new ClosingListener()); setSize(400, 150); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); } // WindowListener-Klasse als innere Klasse public class ClosingListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{ if (cb1.isSelected() && cb2.isSelected())
{ e.getWindow().dispose();
System.exit(0);
}
else JOptionPane.showMessageDialog(c, "Vor dem Schliessen " +
"beide Auswahlfelder selektieren");
}
}
public static void main(String[] args) { new WindowClosingDemo().setVisible(true); } }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 600 – 00 – TH – 02 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 6
6. Applets 6.1. Aufbau und Funktionsweise 6.2. Applet-Tag im HTML-Code 6.3. Java-Applet-API 6.4. Sicherheitsbeschränkungen
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 611 – 00 – TH – 02 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (1) •••• Prinzip eines Applets
◇ Ein Applet ist ein – i.a. kleineres – Java-Programm, das nicht eigenständig durch eine JVM ausgeführt wird sondern innerhalb eines Java-fähigen Web-Browsers bzw eines Applet-Viewers abläuft.
◇ Als Applet-Viewer steht z.B. das im JDK enthaltene Programm appletviewer zur Verfügung.
◇ Ein Applet besitzt immer eine graphische Benutzeroberfläche. Das diese Oberfläche bereitstellende Top-Level-Fenster ist aber nicht eigenständig, sondern befindet sich innerhalb des Browser-Fensters.
◇ Üblicherweise befindet sich der Applet-Code auf einem Server. Er kann nur aus einer HTML-Seite heraus gestartet werden. Hierfür muß die Start-Klasse des Applets durch ein <APPLET>-Tag in der HTML-Seite referiert werden..
◇ Stößt der Browser (bzw. der Applet-Viewer) bei der Interpretation der HTML-Seite auf ein <APPLET>-Tag, so startet er seine – direkt integrierte oder als Plug-In eingebundene – eine JVM enthaltene Java-Laufzeit-Umgebung (JRE – Java Runtime Environment). Diese lädt die Start-Klasse vom Server, instanziert sie und beginnt die Abarbei- tung ihres Codes durch den Aufruf spezieller Methoden.
◇ Die Funktionalität eines als Applet realisierten Java-Programms ist nicht auf die Start-Klasse begrenzt. Ausgehend von der Start-Klasse können – wie bei einem Java-Applikations-Programm – weitere Klassen geladen und instanziert werden. Trotzdem bezieht man den Begriff Applet häufig nur auf die Start-Klasse bzw auf das von ihr im Browser instan- zierte Objekt. •••• Die Klassen Applet und JApplet
◇ Die Start-Klasse eines Applets muß von der Klasse Applet (Package java.applet) abgeleitet sein. Diese Klasse ist ihrerseits über die Klasse Panel von der Klasse Container abgeleitet. Sie verfügt daher über die allen AWT-Komponenten- und Container-Klassen gemeinsamen Fähigkeiten zum Aufbau graphischer Ober- flächen (einschliesslich des Event-Handling-Mechanismus für Benutzereingaben). Die Klasse Applet selbst ergänzt diese durch die besonderen Fähigkeiten und Funktionalitäten, die für Applets benötigt werden. Das von der Browser-JVM instanzierte Objekt der Applet-Start-Klasse bildet einen Container, in den AWT-GUI- Komponenten eingefügt werden können. Defaultmässig besitzt dieser Container ein BorderLayout.
◇ Wenn die vom Applet dargebotene Benutzeroberfläche aus Swing-GUI-Komponenten bestehen soll, muß seine Start- Klasse von der Klasse JApplet (Package javax.swing) abgeleitet sein. Diese ist selbst direkt von der Klasse Applet abgeleitet und ergänzt diese um die besonderen Fähigkeiten und Eigenschaften des Swing-Frameworks. Das von der Browser-JVM instanzierte Objekt einer von JApplet abgeleiteten Start-Klasse bildet somit einen Container für Swing-GUI-Komponenten. Dieser besitzt – wie ein JFrame-Container – eine Content Pane, in die Komponenten einzufügen sind. Defaultmässig besitzt die Content Pane ein BorderLayout. •••• Wesentliche Unterschiede zwischen Applets und Applikationsprogrammen
Applet Applikationsprogramm Start-Klasse von Applet bzw JApplet abgeleitet beliebige Klasse, keine main()-Methode statische main()-Methode Programmstart Laden Start-Klasse in Browser-JVM, Laden Start-Klasse in JVM, Instanzierung, Aufruf spezieller API-Methoden Aufruf von deren main()-Methode Benutzerschnittstelle graphisch Konsole oder graphisch Zugriff zum lokalen durch Security-Manager in Browser-JVM Lesen, Schreiben, Ausführen von Dateisystem i.a. verhindert (Lesen, Schreiben, Ausführen) Dateien i.a. zulässig
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 612 – 00 – TH – 02 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (2)
•••• Demonstrationsbeispiel eines sehr einfachen Applets
◇ Applet-Code (Datei HelloWorldApplet.java)
◇ Einbettende HTML-Datei (HelloWorldApplet.html)
◇ Darstellung des Applets im Browser
◇ Darstellung des Applets durch : appletviewer
HelloWorldApplet.html
import java.applet.Applet; import java.awt.Graphics; public class HelloWorldApplet extends Applet { public void paint(Graphics g) { super.paint(g); g.drawString("This Applet just says : \"Hello world !\"", 70, 25); } }
<HTML> <HEAD> <TITLE> A Simple Applet </TITLE> </HEAD> <BODY> <H3> Ein sehr einfaches Applet : </H3> <APPLET CODE="HelloWorldApplet.class" WIDTH=340 HEIGHT=40>
</APPLET>
</BODY> </HTML>
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 613 – 00 – TH – 03 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (3) •••• Der Lebenszyklus eines Applets
◇ Ein Applet durchläuft während seiner Lebensdauer mehrere Zustände :
◇ Zur Instanzierung eines Applets (genauer : eines Objekts der Applet-Start-Klasse) wird von der JRE des Browsers/ Applet-Viewers der no-arg-Konstruktor der Applet-Start-Klasse aufgerufen. Normalerweise wird für diese ein derartiger Konstruktor nicht explizit definiert, stattdessen wird der Default-nor-arg- Konstruktor verwendet. Dieser ruft lediglich den no-arg-Konstruktor der Basisklasse (Applet oder JApplet) auf. Applets werden also üblicherweise durch ihren Konstruktor nicht initialisiert.
◇ Der Übergang zwischen den verschiedenen Applet-Zuständen wird durch spezielle Memberfunktionen der Klasse Applet, die in der Applet-Start-Klasse gegebenenfalls geeignet überschrieben werden müssen, begleitet. Diese Memberfunktionen werden durch die JRE des Browsers/Applet-Viewers automatisch in verschiedenen Situati- onen aufgerufen. Nach ihrer Ausführung befindet sich das Applet im jeweils neuen Zustand.
◇ Unmittelbar nach der erfolgreichen Instanzierung eines Objekts der Applet-Start-Klasse wird dessen Methode init() aufgerufen. Diese dient zur Initialisierung des Applets und überführt es somit in den Zustand "initialisiert" In ihr werden Anweisungen ausgeführt, die normalerweise in Konstruktoren enthalten sind, also nur einmal während der Lebensdauer eines Applets ausgeführt werden sollen. Typischerweise werden durch diese Methode Datenkompo- nenten initialisiert, die vom Applet dargestellte graphische Oberfläche aufgebaut sowie sonstige dauernd benötigte Resourcen alloziert.
◇ Nach seiner erfolgreichen Initialisierung gelangt das Applet durch Aufruf der Methode start() in den Zustand "gestartet" (aktiv). Diese Methode wird auch immer dann aufgerufen, wenn das im Zustand "angehalten" befindliche Applet erneut aktiviert wird. Dies kann z.B. dann der Fall sein, wenn die HTML-Seite, in die das Applet eingebettet ist, nach dem kurzzeitigen Laden einer anderen Seite erneut angezeigt wird oder das Browser/Applet-Viewer-Fenster nach vorüber- gehender Ikonifizierung wieder voll dargestellt wird. Grundsätzlich kann ein Applet also während seiner Lebensdauer mehrmals zwischen den Zuständen "gestartet" und angehalten" wechseln. Allerdings verhalten sich viele Browser in derartigen Situation anders : Im ersten Fall vernichten sie das Applet und instanzieren es erneut. Im zweiten Fall verbleibt das Applet auch während der Ikonifizierung im Zustand "gestartet".
In der Methode start() sollten alle Aktionen gestartet werden, die zur Ausführung des Applets notwendig sind (z.B. Erzeugung und Start von Animations-Threads, Allokation von nur temporär benötigten Resourcen usw)
◇ Die Methode stop() überführt das Applet in den Zustand "angehalten" (inaktiv). Sie wird unmittelbar vor der Zer- störung eines Applets aufgerufen. Ausserdem kann sie immer dann aufgerufen werden, wenn das Applet vorübergehend nicht dargestellt wird (Laden einer anderen HTML-Seite, Ikonifizierung des Browser-Fensters, s. oben). Die in der Methode start() begonnenen Aktionen und vorgenommenen Allokationen sollen in der Methode stop() wieder angehalten bzw freigegeben werden (� Verhinderung unnötigen Resourcenverbrauchs)
◇ Die Methode destroy() wird aufgerufen, wenn das Applet mit Sicherheit nicht mehr benötigt wird. Es gelangt in den Zustand "zerstört". Danach wird es endgültig beseitigt (aus dem Browser und dem Speicher entfernt). In dieser Methode sollten die in der init()-Methode durchgeführten Allokationen – soweit notwendig – wieder aufgehoben werden (� Funktionalität eines Destruktors !).
◇ Die Standard-Implementierung der vier Lebenszyklus-Methoden (methods for milestones) in der Klasse Applet enthält einen leeren Funktionsrumpf. Bei Bedarf müssen sie in einer Applet-Start-Klasse geeignet überschrieben werden.
instanziert initialisiert init() start()
angehalten
gestartet
zerstört
stop() start()
destroy()
no-arg-Konstruktor paint()
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 614 – 00 – TH – 02 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (4) •••• Die Methode paint()
◇ Die Klasse Applet erbt von der Klasse Container (Package java.awt) u.a. die Methode public void paint(Graphics g)
◇ Diese Methode wird vom JRE des Browsers/Applet-Viewers immer dann aufgerufen, wenn das Applet-Fenster neu gezeichnet werden muß. Dies ist z.B. immer dann der Fall, - wenn das Browser/Applet-Viewer-Fenster und damit das eingebettete Applet-Fenster zum ersten Mal dargestellt wird (Aufruf von paint() nach start()) - wenn das Browser/Applet-Viewer-Fenster wegen einer Größenänderung neu gezeichnet wird - wenn das Applet-Fenster durch andere Fenster überdeckt war und wieder sichtbar wird - wenn im Applet-Code durch den Aufruf von repaint() ein Neuzeichnen veranlasst wird.
◇ Die Methode wird häufig in Applet-Start-Klassen überschrieben, um gezielt bestimmte Graphik-Ausgaben(einschliess- lich Text) direkt in das Applet-Fenster vorzunehmen. (z.B. g.drawString("Hallo") statt Einfügen einer Label-(bzw JLabel-)Komponente mit dem Text "Hallo" in das Applet-Objekt) Um eine einwandfreie Funktion sicherzustellen sollte die überschreibende paint()-Funktion als erstes die von Container geerbte paint()-Funktion aufrufen (� erste Anweisung : super.paint(g)) •••• Anmerkungen zum Erstellen / Testen von Applets
◇ Während ihrer Entwicklung sollten Applets grundsätzlich mit dem JDK-Programm appletviewer getestet werden. Bei diesem Programm ist sichergestellt, dass die HTML-Seite und damit das auszuführende Applet bei jedem Aufruf neu geladen wird. Damit wird immer die neueste Version des Applets ausgeführt.
◇ Browser dagegen speichern den einmal geladenen Code eines Applets im Arbeitsspeicher und besitzen darüberhinaus einen Seiten-Cache. Dadurch wird nach Änderung des Quellcodes eines Applets und seiner Neu-Übersetzung gegebenenfalls nicht die da- durch neu entstandene Version des Applets sondern die im Arbeitsspeicher bzw Cache vorhandene alte Version ausge- führt. Selbst das Neuladen der HTML-Seite aktualisiert nicht das im Arbeitssspeicher vorhandene Applet.
◇ Das Programm appletviewer stellt allerdings nur das Applet und nicht die übrigen Elemente der HTML-Seite dar. •••• Vereinigung von Applet und Applikations-Programm
◇ Es ist möglich, Java-Programme zu erstellen, die sowohl als Applet als auch als Applikations-Programm gestartet werden können.
◇ Um dies zu realisieren, muß die Start-Klasse
▻ sowohl von der Klasse Applet abgeleitet sein und gegebenenfalls die Lebenszyklus-Methoden implementieren
▻ als auch eine geeignete main()-Methode definieren
◇ Damit das Applet und das Applikations-Programm die gleiche GUI besitzen, sollte der Aufbau derselben in einer eigenen Memberfunktion implementiert sein, die sowohl von der init()-funktion als auch der main()-Funktion (bzw gegebenenfalls auch von einem geeigneten Konstruktor) aufgerufen werden kann.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 615 – 01 – TH – 01 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (5-1) •••• Demonstrationsbeispiel zum Lebenszyklus eines Applets
◇ Applet-Code (Datei LifeCycleDemo.java)
◇ Einbettende HTML-Datei (LifeCycleDemo.html)
// LifeCycleDemo.java import java.applet.Applet; import java.awt.*; import javax.swing.*; public class LifeCycleDemo extends JApplet { JLabel info; public LifeCycleDemo() // i.a. nicht ueblich, nur fuer Demo-Zwecke { super(); System.out.println("constructing ... "); } public void init() { info = new JLabel("Demo des Applet Lifecycles", SwingConstants.CENTER); info.setBackground(Color.YELLOW); info.setOpaque(true); getContentPane().add(info); System.out.println("initializing... "); } public void start()
{ System.out.println("starting... "); } public void stop() { System.out.println("stopping... "); } public void destroy() { System.out.println("destroying..."); } public void paint(Graphics g) { super.paint(g); System.out.println("painting ..."); //Zeichnen eines Rechtecks um Fensterflaeche des Applets. g.drawRect(0, 0, getSize().width - 1, getSize().height - 1); } }
<HTML> <HEAD> <TITLE> A Simple Aplet </TITLE> </HEAD> <BODY> <APPLET code="LifeCycleDemo" width="300" height = "100" > </APPLET>
</BODY> </HTML>
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 615 – 02 – TH – 01 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (5-2) •••• Demonstrationsbeispiel zum Lebenszyklus eines Applets, Forts.
◇ Darstellung des Applets durch : appletviewer LifeCycleDemo.html
◇ Beispiel zur Konsolenausgabe Ausführung folgender Aktionen - Start des Applets im Appletviewer - Vergrösserung des Applet-Viewer-Fensters in der Breite (� einmaliger Aufruf von paint()) - Vergrösserung des Applet-Viewer-Fensters in der Höhe (� einmaliger Aufruf von paint()) - Ikonifizierung des Applet-Viewer-Fensters - Herstellung der Normalgroesse des Applet-Viewer-Fensters - Verkleinerung des Applet-Viewer-Fensters in der Breite (� zweimaliger Aufruf von paint()) - Schliessen des Applet-Viewer-Fensters
E:\Java\fhm\ee\vorl\applets>appletviewer LifeCycleDemo.html
constructing ... initializing... starting... painting ... painting ... painting ... stopping... starting... painting ... painting ... painting ... stopping... destroying... E:\Java\fhm\ee\vorl\applets>
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 616 – 01 – TH – 01 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (6-1) •••• Demonstrationsbeispiel zur Vereinigung von Applet und Applikations-Programm
◇ Applet-Code (Datei AppletAndAppliDemo.java)
◇ Einbettende HTML-Datei (AppletAndAppliDemo.html)
// AppletAndAppliDemo.java import java.applet.*; import java.awt.*; import javax.swing.*; public class AppletAndAppliDemo extends JApplet { String progType="Application"; JLabel lab; public void init() { progType="Applet"; setContentPane(buildGUI()); } private Container buildGUI() { JPanel pan=new JPanel(); lab=new JLabel("gestartet als " + progType, SwingConstants.CENTER); lab.setBackground(Color.YELLOW); lab.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); lab.setOpaque(true); pan.add(lab); return pan; } public static void main(String[] args) { AppletAndAppliDemo app = new AppletAndAppliDemo(); JFrame frame = new JFrame("AppletAndAppliDemo"); frame.setContentPane(app.buildGUI()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(330, 150); frame.setVisible(true); } }
<HTML> <HEAD> <TITLE> AppletAndAppliDemo</TITLE> </HEAD> <BODY> <APPLET code="AppletAndAppliDemo" width="330" height = "150" > </APPLET> </BODY> </HTML>
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 616 – 02 – TH – 01 -----------------------------------------------------------------------------------
Aufbau und Funktionsweise von Java-Applets (6-2) •••• Demonstrationsbeispiel zur Vereinigung von Applet und Applikations-Programm, Forts.
◇ Start als Applet mittels : appletviewer AppletAndAppliDemo.html
◇ Start als Applikations-Programm mittels : java AppletAndAppliDemo
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 621 – 00 – TH – 03 -----------------------------------------------------------------------------------
HTML-<APPLET>-Tag (1) •••• Minimalform des <APPLET>-Tags
◇ Vorbemerkung : In der HTML-Syntax wird nicht zwischen Groß- und Klein-Buchstaben unterscheiden.
◇ Das zur Referenzierung eines Applets (genauer : der Applet-Start-Klasse) in einer HTML-Seite benötigte <APPLET>- Tag besitzt Attribute. Diese dienen zur Festlegung bestimmter Eigenschaften des Applets.
◇ In seiner Minimalform muß das <APPLET>- Tag den Namen der Applet-Start-Klasse sowie die Größe (Breite und Höhe) des Applet-Fensters festlegen. Damit muß es wenigstens die folgenden drei Attribute definieren :
▻ code : Dateiname der Bytecode-Datei der Applet-Start-Klasse. Die Extension .class kann weggelassen werden. Die Angabe eines auch Directory-Angaben enthaltenen Dateipfades ist nicht zulässig. Der Dateiname wird relativ zur Codebase-URL der Applet-Start-Klasse ausgewertet. Ohne explizite Festlegung (Attribut codebase) ist diese Codebase-URL gleich der Directory-URL der HTML-Datei, d.h. Applet-Bytecode-Datei und HTML-Datei müssen sich im gleichen Verzeichnis befinden.
▻ width : Breite des Applet-Fensters in Pixel
▻ height : Höhe des Applet-Fensters in Pixel
◇ Beispiel : <APPLET code = "LifeCycleDemo" width = "300" height = "100" > </APPLET>
•••• Allgemeine Form des <APPLET>-Tags
◇ Die Werte der Attribute des <APPLET>-Tags werden als Strings interpretiert. Sie können mit oder ohne String-Quotes (doppelte Hochkommata) angegeben werden.
◇ Die Minimalform des <APPLET>-Tags kann optional ergänzt werden um
▻ weitere Attribute
▻ Parameter, die an das Applet übergeben werden
▻ alternativen HTML-Code, der von Browsern, die das <APPLET>-Tag nicht verstehen, interpretiert wird
◇ Allgemeine Form des <APPLET>-Tags (Die eckigen Klammern [...] kennzeichnen optionale Angaben) : <APPLET
[codebase = codebaseURL] code = appletFile [archive = archivFile] [alt = alternateText] [name = appletInstanceName] width = wpixels heigt = hpixels [align = alignment] [vspace = vpixels] [hspace = hpixels] >
[<PARAM name = appletParameter1 value = parval1 >] [<PARAM name = appletParameter2 value = parval2 >] . . . [alternateHTML] </APPLET>
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 622 – 00 – TH – 02 -----------------------------------------------------------------------------------
HTML-<APPLET>-Tag (2) •••• Optionale Attribute des <APPLET>-Tags
◇ Die folgenden <APPLET>-Tag-Attribute sind optional :
▻ codebase : URL des Verzeichnisses, in dem sich die Bytecode-Datei der Applet-Start-Klasse bzw die Java- Archiv-Datei (s. unten) befindet. Die Angabe kann absolut oder relativ zur Directory-URL der HTML-Datei erfolgen Diese Angabe ist notwendig, wenn die Codebase-URL von der Directory-URL der HTML-Datei abweicht, also Applet-Bytecode-Datei und HTML-Datei sich in verschiedenen Verzeichnissen befinden.
▻ archive : Dateiname einer Java-Archiv-Datei (Extension .jar), in der die Applet-Start-Klasse sowie weitere von dieser verwendete Klassen zusammengefasst sind. Der Dateiname wird relativ zur Codebase-URL ausgewertet.
▻ alt : Alternativer Text, der dargestellt wird, wenn der Browser zwar das <APPLET>-Tag versteht, aber keine Java-Applets ausführen kann
▻ name : Name der Applet-Instanz (genauer : Instanz der Applet-Start-Klasse). Dieser Name ermöglicht es, dass sich mehrere Applets auf der gleichen HTML-Seite gegenseitig lokalisieren und miteinander kommunizieren können.
▻ align : Ausrichtung des Applets gegenüber dem umgebenden Text (Wirkung wie beim <IMG>-Tag) Zulässige Werte : midddle, top, bottom, left, right, texttop, absmiddle, baseline, absbottom
▻ hspace : Horizontaler Abstand (links und rechts) des Applet-Fensters zu den umgebenden Elementen auf der HTML-Seite in Pixel
▻ vspace : Vertikaler Abstand (oben und unten) des Applet-Fensters zu den umgebenden Elementen auf der HTML-Seite in Pixel •••• Parameter in <APPLET>-Tags
◇ Zwischen den Tag-Begrenzungen <APPLET> und </APPLET> können auch Parameter angegeben werden, die von der HTML-Seite an das Applet (genauer : die Instanz der Applet-Start-Klasse) übergeben werden.
◇ Name und Wert eines Parameters sind als Attribut-Werte eines <PARAM>-Tags festzulegen. Sowohl der Name als auch der Wert des Parameters sind jeweils als String anzugeben : <PARAM name = appletParameter value = parval >
◇ Es können beliebig viele Parameter angegeben werden.
◇ In der Klasse Applet existieren Memberfunktionen, mit denen Applets zu diesen Parametern zugreifen können. •••• Alternativer HTML-Code
◇ alternateHTML
Steht für alternativen HTML-Code, der für Browser, die das <APPLET>-Tag nicht verstehen, vorgesehen ist. Er ist zwischen den Tag-Begrenzungen <APPLET> und </APPLET> anzugeben. Typischerweise kann hier alternativ auszugebender Text oder ein Link zu einer alternativ anzuzeigenden Seite ange- geben werden.
◇ Von Browsern, die das <APPLET>-Tag verstehen, wird dieser Code ignoriert.
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 631 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java-Applet-API (1)
•••• Allgemeines
◇ Das Java-Applet-API wird im wesentlichen durch die Klasse Applet und das Interface AppletContext implementiert (beide sind im Package java.applet enthalten). Auf der Basis der engen Beziehung, die zwischen Applets und den sie ausführenden Web-Browsern besteht, stellen sie die folgenden Applet-Fähigkeiten zur Verfügung :
∙ Annahme verschiedener Lebenszyklus-Zustände ("milestones")
∙ Zugriff zu im <APPLET>-Tag enthaltenen Parametern
∙ Einbinden von Graphiken, die in Dateien abgelegt sind
∙ Abspielen von Audio- (Sound-)Dateien
∙ Ausgabe von Informationen in der Statuszeile des Browsers
∙ Darstellung eines neuen HTML-Dokuments im Browser
∙ Kommunikation mit anderen Applets auf derselben HTML-Seite •••• Das Interface AppletContext
◇ Das Interface AppletContext stellt dem Applet einen Zugang zu seiner Umgebung (der das Applet enthaltenen HTML-Seite und den anderen Applets auf dieser Seite) zur Verfügung. Es wird durch die JRE des Browsers/Applet- Viewers implementiert.
◇ Mittels der Methode getAppletContext() kann ein Applet sein AppletContext-"Objekt" ermitteln. Über dieses kann das Applet mit seiner Umgebung kommunizieren.
◇ Methoden des Interfaces (Auszug)
◇ Für einige dieser Methoden stehen gleichnamige Methoden in der Klasse Applet zur Verfügung, die jeweils mittels getAppletContext() das zugehörige AppletContext-"Objekt" ermitteln und dann für dieses die entspre- chende AppletContext-Methode aufrufen. In einem derartigen Fall kann der Applet-Programmierer also auf den expliziten Aufruf von getAppletContext() verzichten und direkt die jeweilige Applet-Methode aufrufen
public Image getImage(URL url) Erzeugung eines Image-Objekts, das die durch die absolute URL url referierte Bild-Datei repräsentiert
public AudioClip getAudioClip(URL url) Erzeugung eines AudioClip-Objekts, das die durch die absolute URL url referierte Audio-Datei repräsentiert
public void showStatus(String msg) Ausgabe des Strings msg in die Statuszeile des Browsers
public void showDocument(URL url) Ersatz der aktuell dargestellten HTML-Seite durch den Inhalt der durch die absolute URL url referierten HTML-Datei (darf von einem Applet-Viewer ignoriert werden)
public void showDocument(URL url, Darstellung des Inhalts der durch die absolute URL url re- String tgt) referierten HTML-Datei in dem durch tgt bezeichneten Browser-Frame (darf von einem Browser / Applet-Viewer ignoriert werden)
public Applet getApplet(String name) Ermittlung der Instanz des Applets mit dem Namen name Dabei ist name der Wert des name-Attributs im <APPLET>-Tag
public Enumeration<Applet> getApplets() Ermittlung aller Applet-Instanzen in der aktuellen HTML- Seite, einschliesslich des Applets, das diese Methode für seinen AppletContext aufruft
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 632 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java-Applet-API (2) •••• Memberfunktionen der Klasse Applet (auszugsweiser Überblick)
◇ Lebenszyklus-Methoden : Aufruf durch JRE des Browsers, Implementierung in der Klasse Applet tut nichts, Bei Bedarf müssen sie in abgeleiteten Klassen geeignet überschrieben werden
◇ einige weitere Methoden :
public void init() Aufruf beim erstmaligen Laden des Applets, dient zur Initialisierung des Applets
public void start() Aufruf beim (Wieder-)Beginn der Applet-Abarbeitung
public void stop() Aufruf beim (vorübergehenden) Anhalten der Applet-Abarbeitung
public void destroy() Aufruf, wenn das Applet zerstört wird, dient zur Freigabe allozierter Resourcen
public String getAppletInfo() Rückgabe von Informationen über das Applet Die Implementierung in Applet liefert null. Die Methode sollte in abgeleiteten Klassen geeignet über- schrieben werden (Autor, Version, Copyright)
public AppletContext getAppletContext() Ermittlung des AppletContext-"Objekts"
public URL getCodeBase() Ermittlung der URL des Directories, das die Datei mit dem Applet-Code enthält
public URL getDocumentBase() Ermittlung der URL der HTML-Datei, in die das Applet eingebettet ist.
public String[][] getParameterInfo() Rückgabe von Informationen über die Parameter, die das Applet "verstehen" kann Die Implementierung in Applet liefert null. Die Methode sollte in abgeleiteten Klassen geeignet über- schrieben werden (s. Java-API-Dokumentation)
public String getParameter(String name) Ermittlung des Werts des Parameters bzw <APPLET>-Tag- Attributs mit dem Namen name
public Image getImage(URL url) Rückgabe eines Image-Objekts, das die durch die absolute URL url referierte Bild-Datei repräsentiert
public Image getImage(URL base, Rückgabe eines Image-Objekts, das die Bild-Datei String rel) repräsentiert, die durch die absolute Basis-URL base und den hierzu relativen Pfad rel referiert wird
public AudioClip getAudioClip(URL url) Rückgabe eines AudioClip-Objekts, das die durch die absolute URL url referierte Audio-Datei repräsentiert
public AudioClip getAudioClip(URL base, Rückgabe eines AudioClip-Objekts, das die Audio-Datei String rel) repräsentiert, die durch die absolute Basis-URL base und den hierzu relativen Pfad rel referiert wird
public void play(URL url) Abspielen der durch url referierten Audio-Datei
public void play(URL base, String rel) Abspielen der durch die Basis-URL url und den hierzu relativen Pfad rel referierten Audio-Datei
public void showStatus(String msg) Ausgabe des Strings msg in die Statuszeile des Browsers
public static final AudioClip newAudioClip(URL url) (ermöglicht Sound in Applikations-Progr.) Rückgabe eines AudioClip-Objekts, das die durch die absolute URL url referierte Audio-Datei repräsentiert
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 633 – 00 – TH – 01 -----------------------------------------------------------------------------------
Java-Applet-API (3)
•••• Zugriff zu Applet- Parametern
◇ Von der HTML-Seite, in die ein Applet eingebettet ist, lassen sich Parameter an das Applet übergeben, die – analog zu Kommandozeilen-Parametern von Applikations-Programmen – die Konfigurierung und Steuerung der Arbeitsweise des Applets ermöglichen (� Applet-Parameter).
◇ Applet-Parameter sind im <APPLET>-Tag mit ihrem Namen und Wert anzugeben : <PARAM name = appletParameter value = parval > Sowohl der Name (name) als auch der Wert (value) werden – unabhängig davon, ob sie in doppelte Hochkommata gesetzt werden oder nicht – als Strings interpretiert Dabei werden beim Namen Groß- und Klein-Buchstaben als gleich betrachtet (case-insensitive), während der Wert dagegen case-sensitive ist. Werden durch die Strings Werte anderer Datentypen dargestellt (z.B. numerische Werte), müssen sie vor ihrer Verwen- dung erst entsprechend konvertiert werden.
◇ Innerhalb des Applet-Codes kann (typischerweise in der init()-Methode) der Wert eines durch seinen Namen name spezifizierten Parameters ermittelt werden mittels der Methode public String getParameter(String name) Für einen im <APPLET>-Tag nicht gesetzten Parameter liefert die Methode den Wert null. Mit dieser Methode lassen sich auch die Werte der <APPLET>-Tag-Attribute ermitteln (name == Attribut-Name)
◇ Beispiele typischer Kandidaten für Applet-Parameter sind - Name und Ort von zu verwendenden Resource-Dateien (z.B. Bild- oder Ton-Dateien) - Werte, die die Erscheinung des Applets beeinflussen (darzustellender Text, Schrift-Stil und -Größe, Anzahl der Bild- wechsel pro sec bei annimierten Applets usw) - Größe darzustellender Fenster usw
◇ Defaultwerte für Applet-Parameter Für alle von einem Applet verwendeten Parameter sollten im Applet-Code sinnvolle Defaultwerte vorgesehen werden. Damit kann eine einwandfreie Funktion des Applets auch dann sichergestellt werden, wenn bestimmte Parameter nicht durch das <APPLET>-Tag bereitgestellt werden.
◇ Beispiel :
... <APPLET code="AppletAPIDemo1" width="250" height = "225" > ... <PARAM name = "SoundPath" value = "sounds/bgsound.mid" > ... </APPLET> ...
public class AppletAPIDemo1 extends JApplet { // ... static final String DEF_SOUNDPATH = "sounds/bark.au"; // ... public void init() { String relSoundPath=getParameter("SoundPath"); if (relSoundPath==null) relSoundPath=DEF_SOUNDPATH; // ... } // ... }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 634 – 00 – TH – 03 -----------------------------------------------------------------------------------
Java-Applet-API (4)
•••• Zugriff zu Resource-Dateien
◇ Mit einigen Applet-API-Funktionen kann zu Resource-Dateien (i.a. Bild- und Audio-Dateien) zugegriffen werden.
◇ Die entsprechenden Methoden benötigen i.a. ein Objekt der Klasse URL als Parameter. Objekte der Klasse URL (Package java.net) repräsentieren in Java die als Uniform Resource Locator (URL) bezeichnete spezielle Darstellung von Resourcen-Adressen im Internet.
◇ Eine URL setzt sich im allgemeinen aus mehreren Komponenten zusammen, im wesentlichen aus : - Protokoll - Rechneradresse - Port-Nummer - Dateipfad (auf dem Rechner) Einige der Komponenten können gegebenenfalls auch fehlen. Sie werden dann durch Default-Werte ersetzt (z.B. Default-Port-Nr des jeweiligen Protokolls). Eine URL kann auch als relative URL angegeben werden. Sie dient dann zur Spezifikation einer Resource relativ zu einer anderen URL. Meist handelt es sich hierbei um einen relativen Dateipfad. Derartige relative URLs werden z.B. häufig innerhalb von HTML-Seiten verwendet. Sie beziehen sich dann auf die Directory-URL der HTML-Seite.
◇ URLs werden üblicherweise als Strings angegeben, z.B. http://archive.ncsa.uiuc.edu:80/SDG/Software/Mosaic/Demo/url-primer.html
◇ Erzeugung eines URL-Objektes aus einem URL-String : Hierzu dient der folgende Konstruktor der Klasse URL : public URL(String spec) throws MalformedURLException Wenn der als Parameter übergebene String spec formal keine URL bezeichnen kann (z.B. unbekanntes Protokoll), wird eine MalformedURLException geworfen. Es existieren noch weitere Konstruktoren mit mehr als einem Parameter. Einige dieser Konstruktoren erlauben es, einzelne Komponenten einer URL getrennt durch Strings anzugeben.
◇ Applets dürfen i.a. nur zu Dateien zugreifen, die sich auf demselben Rechner befinden, von dem sie selbst (d.h. der Byte-Code ihrer Start-Klasse) geladen worden sind. Sinnvollerweise werden derartige Dateien durch eine relative Pfadangabe referiert, die sich entweder auf die Code- Base-URL (Directory-URL der Applet-Start-Klasse) oder auf die Directory-URL der HTML-Seite, in der das Applet eingebettet ist, bezieht.
◇ Die Klasse Applet stellt Memberfunktionen sowohl zum relativen Dateizugriff als auch zur Ermittlung der i.a. hierfür benötigen Basis-URLs zur Verfügung. •••• Einbinden von Graphiken
◇ Mittels den Applet-Memberfunktionen public Image getImage(URL url) public Image getImage(URL base, String rel) wird ein Objekt der Klasse Image aus dem Inhalt der Bild-Datei erzeugt, die durch die absolute URL url bzw die Basis-URL base und den relativen Pfad rel referiert wird.
◇ Mittels des Konstruktors public ImageIcon(Image img) lässt sich aus dem Image-Objekt img ein Objekt der Klasse ImageIcon erzeugen. Die Klasse ImageIcon implementiert das Interface Icon. Die durch Objekte dieser Klasse repräsentierten Bilder können in diversen Swing-Komponten (z.B. JButton, JLabel, JCheckBox) dargestellt werden (Übergabe durch entsprechende Konstruktoren bzw Memberfunktionen. Beispiel : Image img = getImage(getCodeBase(), relPictPath); JButton pictbut=new JButton(new ImageIcon(img));
◇ Alternativ kann ein Image-Objekt auch innerhalb der Methode public void paint(Graphics g) mittels der Graphics-Memberfunktion public boolean drawImage(Image img, ...) dargestellt werden.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 635 – 00 – TH – 01 -----------------------------------------------------------------------------------
Java-Applet-API (5)
•••• Abspielen von Audio-Dateien
◇ Java-Applets können Audio-Dateien abspielen. Ab dem JDK 1.2 steht diese Möglichkeit auch für Applikations-Programme zur Verfügung.
◇ Zum einmaligen Abspielen einer Audio-Datei dienen die Applet-Memberfunktionen public void play(URL url) public void play(URL base, String rel) Die abzuspielende Audio-Datei wird entweder durch eine absolute URL url oder eine Basis-URL base und einen relativen Pfad rel referiert. Sie wird bei jedem Aufruf von play() erneut geladen.
◇ Zum beliebig mehrmaligen und auch ständig wiederholten Abspielen ohne erneutes Laden der Audio-Datei ist es sinnvoll, zunächst ein die Audio-Datei repräsentierendes AudioClip-Objekt zu erzeugen. Dies ermöglichen die Applet-Memberfunktionen public AudioClip getAudioClip(URL url) public AudioClip getAudioClip (URL base, String rel) Auch hier wird die abzuspielende Audio-Datei entweder durch eine absolute URL url oder eine Basis-URL base und einen relativen Pfad rel referiert.
◇ Das Interface AudioClip stellt drei Methoden zur Verfügung : Mit ihnen lässt sich das Abspielen der repräsentierten Audio-Datei ohne erneutes Laden beliebig steuern. Dies kann zum Beispiel in der Methode actionPerformed() eines ActionListener-Objekts als Reaktion auf das Betätigen eines Schaltknopfes (JButton) erfolgen.
◇ Beispiel :
public void play() einmaliges Abspielen der durch das AudioClip-Objekt repräsentierten Audio-Datei
public void loop() ständiges wiederholtes Abspielen der repräsentierten Audio-Datei
public void stop() Beenden des Abspielens der repräsentierten Audio-Datei
public class AppletAPIDemo1 extends JApplet { // ... AudioClip sound; public void init() { // ... sound=getAudioClip(getCodeBase(), relSoundPath); // ... } class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { Object src=e.getSource(); if (src==startbut) sound.loop(); else if (src==stopbut) sound.stop(); } } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 636 – 01 – TH – 01 -----------------------------------------------------------------------------------
Java-Applet-API (6-1) •••• Demonstrationsbeispiel 1 zum Java-Applet-API
◇ Applet-Code (Datei AppletAPIDemo1.java), 1.Teil
import java.applet.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class AppletAPIDemo1 extends JApplet { static final String DEF_LABTEXT = "Demo"; static final String DEF_PICTPATH = "images/dukeWaveRed.gif"; static final String DEF_SOUNDPATH = "sounds/bark.au"; static final int DEF_RAND = 10; Container c; JLabel lab; JButton pictbut; JButton startbut; JButton stopbut; JPanel playpan; AudioClip sound; public void init() { String relSoundPath=getParameter("SoundPath"); if (relSoundPath==null) relSoundPath=DEF_SOUNDPATH; sound=getAudioClip(getCodeBase(), relSoundPath); String labText=getParameter("LabelText"); if (labText==null) labText=DEF_LABTEXT; int rand; try { rand = Integer.parseInt(getParameter("RandBreite")); } catch (NumberFormatException e) { rand=DEF_RAND; } lab=new JLabel(labText, SwingConstants.CENTER); lab.setAlignmentX(Component.CENTER_ALIGNMENT); lab.setBackground(Color.YELLOW); lab.setBorder(BorderFactory.createEmptyBorder(rand, rand, rand, rand)); lab.setOpaque(true); String relPictPath=getParameter("PictPath"); if (relPictPath==null) relPictPath=DEF_PICTPATH; Image img = getImage(getCodeBase(), relPictPath); pictbut=new JButton(new ImageIcon(img)); pictbut.setAlignmentX(Component.CENTER_ALIGNMENT); pictbut.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder(5, 0, 10, 0), pictbut.getBorder())); startbut = new JButton("start play"); startbut.setBackground(Color.GREEN); stopbut = new JButton("stop play"); stopbut.setBackground(Color.RED); playpan = new JPanel(); playpan.add(startbut); playpan.add(stopbut); ActionListener butlis = new ButtonListener(); startbut.addActionListener(butlis); stopbut.addActionListener(butlis);
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 636 – 02 – TH – 01 -----------------------------------------------------------------------------------
Java-Applet-API (6-2) •••• Demonstrationsbeispiel 1 zum Java-Applet-API, Forts.
◇ Applet-Code (Datei AppletAPIDemo1.java), 2.Teil
◇ Einbettende HTML-Datei (AppletAPIDemo1.html)
◇ Darstellung des Applets durch : appletviewer AppletAPIDemo1.html
c=getContentPane(); c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS)); c.add(lab); c.add(pictbut); c.add(playpan); } // Ende init() class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { Object src=e.getSource(); if (src==startbut) sound.loop(); else if (src==stopbut) sound.stop(); } } }
<HTML> <HEAD> <TITLE> AppletAPIDemo1</TITLE> </HEAD> <BODY> <APPLET code="AppletAPIDemo1" width="300" height = "225" > <PARAM name = "LabelText" value = "Demo zum Applet-API" > <PARAM name = "RandBreite" value = 8 > <PARAM name = "PictPath" value = "images/animals/Bird.gif" > <PARAM name = "SoundPath" value = "sounds/bgsound.mid" > </APPLET> </BODY> </HTML>
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 637 – 01 – TH – 01 -----------------------------------------------------------------------------------
Java-Applet-API (7-1) •••• Demonstrationsbeispiel 2 zum Java-Applet-API (Demo zu showStatus())
◇ Applet-Code (Datei AppletAPIDemo2.java)
// AppletAPIDemo2.java
// Demo zu showStatus() import java.applet.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class AppletAPIDemo2 extends JApplet { static final String DEF_PICTPATH = "images/javalogo52x88.gif"; Container c; JLabel textlab; JLabel pictlab; public void init() { textlab=new JLabel("Demo zu showStatus()", SwingConstants.CENTER); textlab.setAlignmentX(Component.CENTER_ALIGNMENT); textlab.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); String relPictPath=getParameter("PictPath"); if (relPictPath==null) relPictPath=DEF_PICTPATH; Image img = getImage(getCodeBase(), relPictPath); pictlab=new JLabel(new ImageIcon(img)); pictlab.setAlignmentX(Component.CENTER_ALIGNMENT); pictlab.setBorder(BorderFactory.createLineBorder(Color.BLACK)); c=getContentPane(); c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS)); c.add(textlab); c.add(pictlab); MouseListener mouselis = new AppletMouseListener(); addMouseListener(mouselis); } class AppletMouseListener extends MouseAdapter { public void mouseEntered(MouseEvent e) { showStatus("Gruess Gott Mouse !"); } public void mouseExited(MouseEvent e) { showStatus("Auf Wiedersehen Mouse !"); } } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 637 – 02 – TH – 01 -----------------------------------------------------------------------------------
Java-Applet-API (7-2) •••• Demonstrationsbeispiel 2 zum Java-Applet-API (Demo zu showStatus()), Forts.
◇ Einbettende HTML-Datei (AppletAPIDemo2.html)
◇ Darstellung des Applets durch : appletviewer AppletAPIDemo2.html
<HTML> <HEAD> <TITLE> AppletAPIDemo2</TITLE> </HEAD> <BODY> <APPLET code="AppletAPIDemo2" width="300" height = "150" > <PARAM name = "PictPath" value = "images/dukeWaveRed.gif" > </APPLET> </BODY> </HTML>
Mouse-Zeiger über dem Applet
Mouse-Zeiger wieder ausserhalb desApplets
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 641 – 00 – TH – 02 -----------------------------------------------------------------------------------
Sicherheitsbeschränkungen bei Java-Applets (1)
•••• Allgemeines
◇ Ein über das Netz geladenes lokal ablaufendes Programm stellt für den lokalen Rechner prinzipiell ein Sicherheits- risiko dar.
◇ Um dieses Sicherheitsrisiko aufzuheben, muß sichergestellt werden, dass ein derartiges Programm keine unbefugten Aktionen (wie z.B. Zugriff zum lokalen Dateisystem, Start lokaler Programme usw) durchführen kann.
◇ Als Mechanismus zum Schutz vor der unbefugten Ausführung sicherheitsrelevanter Operationen ist in Java ein so- genannter Security-Manager vorgesehen. Ein Security-Manager ist ein Objekt der Klasse SecurityManager oder einer davon abgeleiteten Klasse, das in jedem Java-Programm installiert sein kann. Ein SecurityManager-Objekt stellt Methoden zur Verfügung, die die Zulässigkeit diverser sicherheitsrelevanter Operationen überprüfen. Falls im Programm ein SecurityManager-Objekt installiert ist, wird von den Java-Bibliotheks-Klassen vor der Ausführung einer entsprechenden sicherheitsrelevanten Operation die zugehörige SecurityManager-Überprüfungs- Methode aufgerufen. Falls die Ausführung der überprüften Operation unzulässig ist, wird eine SecurityException geworfen.
◇ Defaultmässig besitzt ein Applikations-Programm keinen Security-Manager. Soll die Ausführung bestimmter sicherheitsrelevanter Operationen für ein Applikations-Programm beschränkt werden, muß es selbst ein geeignetes SecurityManager-Objekt erzeugen und installieren.
◇ Die existierenden java-fähigen Browser und Applet-Viewer dagegen installieren beim Start einen Security-Manager. Damit unterliegt die Ausführung von Applets den durch diesen zur Verfügung gestellten Sicherheits-Überprüfungen. � Für die Ausführung von Applets gelten also bestimmte Sicherheitsbeschränkungen, die verhindern, dass unbefugte Aktionen ausgeführt werden können. •••• Prinzipielle Sicherbeschränkungen bei Applets
◇ Der Umfang der für Applets geltenden Sicherheitsbeschränkungen hängt von dem jeweiligen Browser / Applet-Viewer und dem installierten Security-Manager sowie von der Vertrauenswürdigkeit des Applets ab.
◇ Standardmässig werden alle von einem anderen Rechner geladen Applets als nicht-vertrauenswürdig betrachtet. Sie unterliegen damit i.a. allen nachfolgend aufgelisteten Sicherheitsbeschränkungen.
◇ Vom lokalen Dateisystem geladene Applets werden dagegen als vertrauenswürdig betrachtet. Für sie gelten die meisten der Sicherheitsbeschränkungen nicht. Analoges gilt für signierte Applets, auch wenn sie von einem entfernten Rechner geladen werden. Sie werden ebenfalls als vertrauenswürdig betrachtet.
◇ Typischerweise gelten für nicht-vertrauenswürdige Applets die folgenden Sicherheitsbeschränkungen :
∙ kein Zugriff (weder lesend noch schreibend) zum lokalen Dateisystem (Client-Datei-System)
∙ kein Aufbau von Netzwerkverbindungen, außer zu dem Rechner von dem das Applet jeweils stammt (Host-Rechner)
∙ kein Start von Programmen auf dem ausführenden (lokalen) Rechner (Client-Rechner)
∙ kein zusätzliches Laden von Bibliotheken (über die vom Browser geladene Standard-Bibliothek hinaus)
∙ keine Definition von native-Methoden
∙ kein Top-Level-Fenster ohne Warnhinweis erzeugen
∙ keine Beendigung des Browsers (mittels System.exit(i))
∙ eingeschränkter Zugriff zur System-Umgebung (System Properties)
◇ Für vom Applet-Viewer des JDK ausgeführte Applets gelten viele der o.a. Beschränkungen nicht
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 642 – 00 – TH – 01 -----------------------------------------------------------------------------------
Sicherheitsbeschränkungen bei Java-Applets (2) •••• Beschränkungen beim Zugriff zur System-Umgebung (System-Properties)
◇ Applets können zu einigen, aber nicht allen System Properties zugreifen.
◇ Der Zugriff zu folgenden System Properties ist gemäß der Java-Dokumentation für Applets nicht möglich :
∙ java.home Java-Installations-Directory
∙ java.class.path Wert der CLASSPATH-Environment-Variablen
∙ user.name Benutzer-Name des aktuellen Benutzers
∙ user.home Heimat-Verzeichnis des aktuellen Benutzers
∙ user.dir aktuelles Arbeitsverzeichnis des aktuellen Benutzers
◇ Zu den folgenden System Properties sollte dagegen von Applets aus jedem Browser bzw Applet-Viewer zugegriffen werden können :
∙ java.version Nummer der Java-Version
∙ java.vendor Kennzeichnung des Java-Lieferanten
∙ java.vendor.url URL des Java-Lieferanten
∙ java.class.version Java-Klassen-Versions-Nummer
∙ os.name Name des Betriebssystems
∙ os.arch Prozessor-Architektur auf der das Betriebssystem läuft
∙ os.version Versions-Nummer des Betriebssystems
∙ file.separator Trennzeichen in Pfadangaben
∙ path.separator Trennzeichen zwischen Pfaden
∙ line.separator Zeilenende-Zeichen
HOCHSCHULE MUENCHEN FKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 700 – 00 – TH – 03 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 7
7. Multithreading 7.1. Erzeugung von Threads 7.2. Beenden von Threads 7.3. Synchronisation von Threads 7.4. Thread-Kommunikation über Pipes
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 711 – 00 – TH – 02 -----------------------------------------------------------------------------------
Erzeugung von Threads in Java (1)
•••• Prinzip von Threads
◇ Unter einem Thread ("Ablauffaden") versteht man einen Kontrollfluß innerhalb eines Prozesses, in dem Anwei- sungen eines Programms sequentiell abgearbeitet werden. Dabei können innerhalb eines Prozesses mehrere Threads existieren, die nebenläufig (parallel bzw quasi-parallel) ablaufen � Multithreading. Threads ermöglichen also eine Nebenläufigkeit innerhalb eines Programms (Prozesses)
◇ Jeder Thread besitzt einen eigenen Programmzähler und einen eigenen Stack, teilt sich aber mit den anderen Threads desselben Programms fast alle anderen Resourcen, insbesondere einen gemeinsamen Adressraum. Bezüglich der Nebenläufigkeit verhalten sich Threads zwar prinzipiell wie eigenständige Prozesse, im Unterschied zu diesen verfügen sie aber weitgehend über eine gemeinsame Ablaufumgebung. � "leichtgewichtige" Prozesse.
◇ Typischerweise ist die in einem Thread abgearbeitete Anweisungsfolge in einer Funktion (Prozedur) zusammenge- fasst. Diese kann natürlich weitere Funktionen aufrufen, die dann ebenfalls innerhalb des Threads ausgeführt werden.
◇ Ein Thread befindet sich zu jedem Zeitpunkt in genau einem von mehreren möglichen Zuständen
◇ Ein Thread wird als aktiv (active, alive) bezeichnet, wenn seine Anweisungsfolge gestartet aber noch nicht beendet worden ist. •••• Threads in Java
◇ Jeder ("schwergewichtige") Prozeß, d.h. jedes in Ausführung befindliche Programm, enthält wenigstens einen Thread. In Java-Programmen wird dieser durch die Abarbeitung der main()-Funktion der Startklasse gebildet. Bei Programmen mit graphischer Oberfläche werden darüber hinaus automatisch weitere Threads erzeugt. U.a. gibt es den event-dispatching Thread, der für das Zustellen von Ereignissen und deren Bearbeitung zuständig ist.
◇ Grundsätzlich ist die Erzeugung weiterer Threads in Java sehr einfach. Das Konzept einer Nebenläufigkeit mit Threads ist direkt in die Sprache integriert worden (Sprachkomponenten zur Synchronisation) und wird durch geeignete Bibliothekskomponenten effizient unterstützt.
◇ Threads in Java besitzen eine Priorität ,einen Namen und – ab dem JDK 5.0 – eine ID (positiver long-Wert).
◇ Threads in Java sind in Thread-Gruppen zusammengefasst. Jeder Thread gehört zu einer Thread-Gruppe
◇ Threads werden in Java durch Objekte gekapselt. Prinzipiell kann ihre Gesamt-Funktionalität dabei auf zwei Objekte aufgeteilt sein :
▻ Ein Objekt definiert die vom Thread auszuführende Anweisungsfolge Es legt die durchzuführende Arbeit ("work") fest � "Thread-Arbeits-Objekt", Thread-Target-Objekt.
▻ Ein Objekt dient zur Verwaltung und Steuerung (Starten, Beenden, Unterbrechen, Weiterlaufen) der Thread-Abar- beitung. Es führt die Arbeit durch ("worker") � "Thread-Arbeiter-Objekt", Thread-Verwaltungs-Objekt. Die Funktionalität von beiden kann auch in einem einzigen Objekt zusammengefasst sein.
◇ Kern der Thread-Unterstützung durch die Standardbibliothek sind (enthalten im Package java.lang) :
▻ das Interface Runnable
▻ die Klasse Thread •••• Das Interface Runnable
◇ Alle Thread-Target-Objekte müssen Instanzen einer Klasse sein, die das Interface Runnable implementiert.
◇ Das Interface Runnable deklariert eine einzige Methode : public void run()
◇ Die Methode run() muß in einer implementierenden Klasse so überschrieben werden, dass sie die innerhalb des Threads auszuführende Anweisungsfolge definiert.
◇ Der Start eines Threads bewirkt die Abarbeitung der run()-Methode des zum Thread gehörenden Target-Objekts Der Aufruf dieser Methode erfolgt automatisch – indirekt – durch die JVM
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 712 – 01 – TH – 03 ------------------------------------------------------------------------------------
Erzeugung von Threads in Java (2-1) •••• Die Klasse Thread (Package java.lang)
◇ Diese Klasse definiert die Funktionalität zur Verwaltung/Steuerung von Threads. Jedes Thread-Verwaltungs-Objekt muß eine Instanz dieser Klasse oder einer von ihr abgeleiteten Klasse sein.
◇ Ein Thread-Objekt kann bei seiner Erzeugung mit einem Thread-Target-Objekt assoziiert werden.
◇ Die Klasse Thread implementiert selbst auch das Interface Runnable. Falls mit einem Thread-Objekt ein Thread-Target-Objekt assoziiert ist, ruft die in der Klasse Thread definierte run()-Methode die run()-Methode des Target-Objekts auf. Andernfalls besitzt die run()-Methode eine leere Funktionalität. In einer von Thread abgeleiteten Klasse kann die run()-Methode aber so überschrieben werden, dass sie die volle Arbeits-Funktionalität eines Threads enthält. Damit lassen sich Thread-Verwaltungs- und Thread-Arbeits-Funk- tionalität in einem einzigen Objekt zusammenfassen.
◇ Die Klasse Thread definiert als eingebettete Top-Level-Klasse den Aufzählungstyp Thread.State : public static enum State extends Enum<Thread.State> { ... } Die Objekte dieses Aufzählungstyps (== Aufzählungskonstante) kennzeichnen die verschiedenen Thread-Zustände.
◇ Die Klasse definiert drei statische öffentliche Datenkomponenten als Konstanten für die Prioritätsfestlegung :
◇ Konstruktoren der Klasse Thread (Auswahl)
◇ Memberfunktionen zur Thread-Steuerung (Auswahl)
public static final int MIN_PRIORITY minimale Priorität, die ein Thread haben kann
public static final int MAX_PRIORITY maximale Priorität, die ein Thread haben kann
public static final int NORM_PRIORITY Default-Priorität, die einem Thread zugeordnet wird
public Thread() Erzeugung eines Thread-Objekts, das mit keinem Thread-Target-Objekt assoziiert ist und einen vom System vergebenen Default-Namen besitzt
public Thread(Runnable tgt) Erzeugung eines Thread-Objekts, das mit dem Thread-Target-Objekt tgt assoziiert ist und einen vom System vergebenen Default-Namen besitzt
public Thread(Runnable tgt, Erzeugung eines Thread-Objekts, das mit dem Thread-Target-Objekt tgt String name) assoziiert ist und den Namen name besitzt
public Thread(String name) Erzeugung eines Thread-Objekts, das mit keinem Thread-Target-Objekt assoziiert ist und den Namen name besitzt
public void start() Start der Ausführung des Threads. Die Methode veranlasst die JVM die run()-Methode des Thread-Objekts aufzurufen
public void run() Aufruf der run()-Methode eines assozierten Thread-Target-Objekts bzw leere Funktionalität, falls kein Thread-Target-Objekt assoziiert ist Muss in abgeleiteten Klassen geeignet überschreiben werden
public void interrupt() Setzen des Abbruch-Flags des Threads bzw – falls der Thread in einem Wartezustand ist – Senden einer InterruptedException an den Thread
public final void join() Warten auf die Beendigung des Threads
public static void sleep(long ms) Übergang des aktuellen Threads in den Wartezustand für ms Millisek Kann gegebenenfalls eine InterruptedException werfen
public static void yield() (temporäre) Freigabe der CPU durch den laufenden Thread
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 712 – 02 – TH – 04 ------------------------------------------------------------------------------------
Erzeugung von Threads in Java (2-2 ) •••• Die Klasse Thread, Forts.
◇ Memberfunktionen zur Information über den Thread-Zustand
◇ Memberfunktionen zurInformation über und Beeinflussung von Thread-Eigenschaften (Auswahl)
◇ Zur Synchronisation und damit zur Steuerung von Threads dienen auch einige Methoden der Klasse Object :
▻ public final void wait() public final void wait(long timeout) public final void wait(long timeout, int nanos)
▻ public final void notify()
▻ public final void notifyAll() Diese Methoden werden aber nicht als Memberfunktionen des zu steuernden Threads aufgerufen, sondern als Memberfunktion des Objekts, zu dem der Zugriff synchronisiert werden soll. Sie beeinflussen jeweils den Thread, der die Zugriffssperre (Lock) zu diesem Objekt besitzt, bzw ein oder alle Objekte, die auf die Freigabe und damit den Besitz des Locks für das Objekt warten.
public Thread.State getState() Rückgabe des Thread-Zustands (ab dem JDK 5.0)
public boolean isInterrupted() Überprüfung des Abbruch-Flags des Threads, liefert true, wenn das Abbruch-Flag gesetzt ist Das Abbruch-Flag selbst wird nicht beeinflusst public static boolean interrupted() Überprüfung des Abbruch-Flags des aktuellen Threads liefert true, wenn das Abbruch-Flag gesetzt ist Das Abbruch-Flag wird rückgesetzt public boolean isAlive() Überprüfung, ob der Thread noch aktiv ist (gestartet und noch nicht beendet) liefert true, wenn der Thread noch aktiv ist
public long getID() Rückgabe der Thread-ID (ab dem JDK 5.0)
public final String getName() Rückgabe des Thread-Namens
public final void setName(String name) Ändern des Thread-Namens auf name
public final int getPriority() Rückgabe der Thread-Priorität
public final void setPriority(int prio) Ändern der Thread-Priorität auf prio
public final ThreadGroup getThreadGroup() Rückgabe einer Referenz auf das ThreadGroup-Objekt der Thread-Gruppe, zu der der Thread gehört
public static int activeCount() Rückgabe der Anzahl der aktiven Threads, die sich in der Thread-Gruppe des aktuell laufenden Threads befinden
public static Thread currentThread() Rückgabe einer Referenz auf das Thread-Objekt des aktuell ausgeführten Threads
public String toString() Rückgabe einer String-Repräsentation des Threads. Diese enthält den Namen und die Priorität des Threads sowie den Namen seiner Thread-Gruppe
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 712 – 03 – TH – 03 ------------------------------------------------------------------------------------
Erzeugung von Threads in Java (2-3 ) •••• Der Aufzählungstyp Thread.State (Package java.lang)
◇ static-Komponente der Klasse Thread � eingebetteter Top-Level-Typ
◇ Der Typ ist abgeleitet von der parameterisierten Klasse Enum<Thread.State>
◇ Objekte dieses Typs (== Aufzählungskonstante) dienen zur Kennzeichnung der verschiedenen Thread-Zustände
◇ Die definierten Aufzählungskonstanten (und damit Thread-Zustände) sind :
◇ Die folgenden von der Klasse Enum<Thread.State> geerbten Methoden werden durch Thread.State überschrieben :
▻ Die Funktion gibt ein Array der definierten Aufzählungskonstanten zurück. Die Reihenfolge der Konstanten im Array entspricht ihrer Definitionsreihenfolge
▻ Die Funktion gibt die Aufzählungskonstante (d.h. das entsprechende Thread.State-Objekt) mit dem Namen name zurück. Die Funktion wirft eine Exception vom Typ IllegalArgumentException, wenn name keine definierte Aufzählungskonstante bezeichnet.
NEW Zustand nach Erzeugung eines Thread-Objekts vor Aufruf der start()-Methode
RUNNABLE Der Thread wird gerade abgearbeitet oder ist ablaufbereit (wartet auf CPU)
BLOCKED Der Thread wartet auf die Freigabe eines Monitor-Locks (zu Beginn der Ausführung einer synchronized-Anweisung/Methode bzw nach Aufwecken durch notify() auf das durch den Aufruf von wait() gewartet wurde)
WAITING Der Thread wartet auf einen anderen Thread um weiterlaufen zu können (z.B. Warten auf notify() eines anderen Threads nach dem Aufruf von wait() oder Warten auf die Beendigung eines Threads für den join() aufgerufen wurde)
TIMED_WAITING Der Thread wartet auf den Ablauf einer festgelegten Zeit (z.B. nach Aufruf von sleep() oder wait() mit Timeout oder join() mit Timeout)
TERMINATED Der Thread ist beendet (Methode run() ist beendet)
public static final Thread.State[] values()
public static Thread.State valueOf(String name)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 713 – 01 – TH – 02 -----------------------------------------------------------------------------------
Erzeugung von Threads in Java (3-1 ) •••• Demonstrationsprogramm zu den standardmässig erzeugten Threads einfacher GUI-Programme
◇ Quellcode (Datei BasicThreadDemo.java)
// BasicThreadDemo.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class BasicThreadDemo extends JFrame { Container c; JButton but; public BasicThreadDemo() { super("BasicThreadDemo"); c=getContentPane(); c.setLayout(new FlowLayout()); but = new JButton("Print Current Thread Info"); c.add(but); Thread nthr = new Thread("Leer-Thread"); System.out.print(nthr + " ID : " + nthr.getId()); System.out.println(" (State : " + nthr.getState() + ")"); ActionListener actlis = new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("\n" + Thread.currentThread() + " (im Event-Listener)"); threadInfo(); } }; but.addActionListener(actlis); setSize(300, 180); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); System.out.println(Thread.currentThread() + " (im Konstruktor)"); } public void threadInfo() { System.out.println(); Thread[] thrarr = new Thread[Thread.activeCount()]; int threadAnz = Thread.currentThread().getThreadGroup().enumerate(thrarr); System.out.println("ThreadGroup enthaelt " + threadAnz + " aktive Threads : \n"); for (Thread thr : thrarr) { System.out.print(thr + " ID : " + thr.getId()); System.out.println(" (State : " + thr.getState() + ")"); } System.out.println(); } public static void main(String[] args) { System.out.println("Thread-Min-Priority : " + Thread.MIN_PRIORITY); System.out.println("Thread-Max-Priority : " + Thread.MAX_PRIORITY); System.out.println("Thread-Norm-Priority : " + Thread.NORM_PRIORITY); System.out.println("\n" + Thread.currentThread() + " (in main())"); new BasicThreadDemo().setVisible(true); while(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 713 – 02 – TH – 02 -----------------------------------------------------------------------------------
Erzeugung von Threads in Java (3-2 ) •••• Demonstrationsprogramm zu den standardmässig erzeugten Threads einfacher GUI-Programme
◇ Programmstart und -ausgabe
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 714 – 00 – TH – 01 -----------------------------------------------------------------------------------
Erzeugung von Threads in Java (4) •••• Möglichkeiten zur Erzeugung von Threads in Java
◇ Es existieren zwei grundsätzliche Möglichkeiten
◇ Erste Möglichkeit : Zusammenfassung der Thread-Target- und der Thread-Verwaltungs-Funktionalität in einem einzigen Objekt. Die Klasse dieses Thread-Objekts (MyThread) muß von der Klasse Thread abgeleitet werden und die Methode run() so überschreiben, dass sie die vom Thread auszuführenden Anweisungsfolge definiert. class MyThread extends Thread
{
public void run()
{ // ...
}
// ...
}
Der Thread wird durch Aufruf der von Thread geerbten Methode start() für ein erzeugtes MyThread- Objekt gestartet. Der Aufruf von start() bewirkt den Aufruf der überschriebenen Methode run(). new MyThread().start();
◇ Zweite Möglichkeit : Aufteilung der Thread-Gesamt-Funktionalität auf ein Thread-Target- und ein Thread-Verwaltungs-Objekt. Die Klasse des Thread-Target-Objekts (MyRun) muß das Interface Runnable implementieren und die Methode run()mit der vom Thread auszuführenden Anweisungsfolge definieren. Das Thread-Verwaltungs-Objekt ist eine Instanz der Klasse Thread. Diesem ist bei seiner Erzeugung im Konstruk- tor eine Instanz der Thread-Target-Klasse MyRun zu übergeben. class MyRun implements Runnable
{
public void run()
{ // ...
}
// ...
}
Gestartet wird der Thread durch Aufruf der Methode start() für das erzeugte Thread-Objekt. Der Aufruf dieser Methode bewirkt den Aufruf der Methode run() des gleichen Objekts. Diese wiederum ruft
die run()-Methode des dem Thread-Objekt übergebenen MyRun-Objekts auf. new Thread(new MyRun()).start();
ThreadThreadThreadThread
+run():void+start():void
MyThreadMyThreadMyThreadMyThread
+run():void
interfaceRunnableRunnableRunnableRunnable
+run():void
MyRunMyRunMyRunMyRun
+run():void
ThreadThreadThreadThread
+run():void+start():void
interfaceRunnableRunnableRunnableRunnable
+run():void
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 715 – 00 – TH – 01 -----------------------------------------------------------------------------------
Erzeugung von Threads in Java (5) •••• Demonstrationsprogramm zu Threads (Thread-Klasse von Thread abgeleitet)
◇ Quellcode (Datei SimpleThreadDemo1.java)
◇ Programmstart und -ausgabe
// SimpleThreadDemo1.java public class SimpleThreadDemo1 extends Thread { private String wort; private int delay; public SimpleThreadDemo1(String wrt, int del) { wort = wrt; delay = del; } public void run() { try
{ while(true)
{ System.out.print(wort + ' '); Thread.sleep(delay);
}
}
catch(InterruptedException e)
{ return;
}
} public static void main(String[] args) { new SimpleThreadDemo1("PING", 100).start(); new SimpleThreadDemo1("pong", 33).start(); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 716 – 00 – TH – 01 -----------------------------------------------------------------------------------
Erzeugung von Threads in Java (6) •••• Demonstrationsprogramm zu Threads (Thread-Target-Klasse implementiert Runnable)
◇ Quellcode (Datei SimpleThreadDemo1.java)
◇ Programmstart und -ausgabe
// SimpleThreadDemo2.java public class SimpleThreadDemo2 implements Runnable { private String wort; private int delay; public SimpleThreadDemo2(String wrt, int del) { wort = wrt; delay = del; } public void run()
{ try
{ while(true)
{ System.out.print(wort + ' '); Thread.sleep(delay);
}
}
catch(InterruptedException e)
{ return;
}
}
public static void main(String[] args) { new Thread(new SimpleThreadDemo2("PING", 100)).start(); new Thread(new SimpleThreadDemo2("pong", 33)).start(); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 721 – 00 – TH – 02 -----------------------------------------------------------------------------------
Beenden von Threads in Java (1) •••• Normales Ende eines Threads
◇ Normalerweise läuft ein Thread solange wie seine run()-Methode ausgeführt wird. Er wird erst beendet, wenn auch die letzte Anweisung dieser Methode abgearbeitet worden ist.
◇ Ein Thread lässt sich nur einmal mittels start() starten. D.h. ein einmal beendeter Thread kann nicht noch einmal ablaufen. Soll die im Thread realisierte Funktionalität nochmals ausgeführt werden, muss ein neues Thread-Objekt erzeugt und für dieses dann start() aufgerufen werden. •••• Vorzeitiges Beenden eines Threads
◇ Der Aufruf der Methode System.exit(...) in irgendeinem Thread bewirkt, dass die JVM und damit alle Threads beendet werden.
◇ Tritt in einemThread eine Exception auf, die nicht gefangen wird, führt das ebenfalls zum vorzeitigen Ende des Threads.
◇ Häufig läuft ein Thread in einer Schleife, die gezielt zu einem bestimmten Zeitpunkt von aussen – durch einen anderen Thread – beendet werden soll, wodurch dann i.a. auch der Thread sein Ende erreicht Ohne diese Einwirkung von aussen würde der Thread meist in einer Endlosschleife laufen.
◇ Ein derartiges gezieltes vorzeitiges Beenden einen Threads kann dadurch erreicht werden, dass der Thread an geeig- neter Stelle innerhalb der Schleife ein Abbruchkriterium überprüft, dass von aussen gesetzt werden kann. Prinzipiell kann hierfür eine explizit dafür vorgesehene Datenkomponente (z.B. vom Typ boolean) eingesetzt werden.
◇ Einfacher und i.a. effizienter ist es aber, hierfür auf einen in der Klasse Thread implementierten Mechanismus zu- rückzugreifen. Dieser beruht auf den Memberfunktionen interrupt () und isInterrupted().
◇ Die Methode interrupt() führt bei dem Thread-Objekt, für das sie aufgerufen wird, zum Setzen eines Abbruch-Flags, falls sich der zugehörige Thread nicht in einem Wartezustand befindet. Falls sich der Thread in einem Wartezustand befindet (z.B. ausgelöst durch den Aufruf von Thread.sleep(...)), wird an ihn eine InterruptedException geschickt, die den Wartezustand beendet. Das Abbruch-Flag wird nicht gesetzt (es wird sogar rückgesetzt, falls es gesetzt gewesen war). Um auch in diesem Fall ein Setzen des Abbruch-Flags zu erreichen, muss der zugehörige Exception-Handler seinerseits die Methode interrupt() aufrufen. Da sich der Thread nun nicht mehr in einem Wartezustand befindet, wird da- durch das Abbruch-Flag gesetzt.
◇ Mit der Methode isInterrupted() kann der Thread den Zustand seines Abbruch-Flags überprüfen. Falls die Methode true zurückliefert, war das Flag gesetzt. Dies sollte dann zum Beenden der Schleife führen.
◇ Beispiel :
public void run() { while (!isInterrupted()) { try { // tue etwas Thread.sleep(500); } catch(InterruptedException e) { interrupt(); } } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 722 – 01 – TH – 02 -----------------------------------------------------------------------------------
Beenden von Threads in Java (2-1) •••• Demonstrationsprogramm zum gezielten vorzeitigen Beenden eines Threads, Teil 1
◇ Quellcode der Klasse BlinkDemo (Datei BlinkDemo.java)
◇ Vom Programm erzeugtes Fenster (beide Blinkzustände)
// BlinkDemo.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class BlinkDemo extends JFrame { Container c; BlinkPanel blkpan; BlinkThread blkthr = null; public BlinkDemo() { super("BlinkDemo"); c=getContentPane(); blkpan = new BlinkPanel(Color.GREEN, Color.RED); c.add(blkpan); setSize(250, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); blkpan.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (blkthr==null || !blkthr.isAlive()) { blkthr = new BlinkThread(BlinkDemo.this); blkthr.start(); } else blkthr.interrupt(); } } ); } public void blink() { blkpan.chgCol(); repaint(); } public static void main(String[] args) { BlinkDemo blkdemo = new BlinkDemo(); blkdemo.setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 722 – 02 – TH – 02 -----------------------------------------------------------------------------------
Beenden von Threads in Java (2-2) •••• Demonstrationsprogramm zum gezielten vorzeitigen Beenden eines Threads, Teil 2
◇ Quellcode der Klasse BlinkPanel (Datei BlinkPanel.java)
◇ Quellcode der Klasse BlinkThread (Datei BlinkThread.java)
// BlinkPanel.java import java.awt.*; import javax.swing.*; public class BlinkPanel extends JPanel { Color bgc; Color vgc; boolean equcol; public BlinkPanel(Color bg, Color vg) { bgc=bg; vgc=vg; setBackground(bgc); setOpaque(true); equcol=false; } public void chgCol() { equcol=!equcol; } public void paint(Graphics g) { super.paint(g); if (equcol) setForeground(bgc); else setForeground(vgc); g.fillOval(20, 20, getWidth()-40, getHeight()-40); } }
// BlinkThread.java public class BlinkThread extends Thread { private BlinkDemo blkdem; public BlinkThread(BlinkDemo bd) { blkdem=bd; } public void run()
{ while (!isInterrupted())
{ blkdem.blink();
try
{ Thread.sleep(500); } catch (InterruptedException e) {interrupt();}
}
}
}
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 731 – 00 – TH – 05 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (1) •••• Probleme bei Nebenläufigkeit
◇ Multithreading dient zur Realisierung einer Nebenläufigkeit innerhalb eines Prozesses. Nebenläufigkeit ermöglicht aber einen konkurierenden Zugriff zu denselben Resourcen (z.B. Daten). Dies kann zu erheblichen Problemen führen. Die beiden wichtigsten dieser Probleme sind : - Zugriffs-Wettlauf (race condition) - Verklemmung (deadlock)
◇ Zugriffs-Wettlauf (race condition) Wenn zwei oder mehr Threads konkurierend zu denselben Daten zugreifen und wenigstens einer dieser Threads die Daten verändert, - kann es zu inkonsistenten und in der Folge zu fehlerhaften Datenzuständen kommen (z.B. gleichzeitige bzw zeitlich verzahnte Durchführung je eines read-modify-write-Zyklus auf die gleichen Daten durch zwei verschiedene Threads, allgemein : Leser-Schreiber-Problem) - können von den Threads erzeugte Ergebnisse zeitabhängig sein (Ergebnisse hängen von der Zugriffsreihenfolge ab, typisch : Produzenten-Verbraucher-Problem) Zur Vermeidung dieser Probleme muss der konkurierende Zugriff synchronisiert werden. Durch eine derartige Synchronisation wird sichergestellt, dass ein "kritischer" Datenzugriff immer nur von einem Thread ausgeführt werden kann. Nur ein Thread besitzt die Zugriffsberechtigung zu den Daten (allg. : Betriebsmittel). Andere Threads, die zu den gleichen Daten (Betriebsmittel) zugreifen wollen, müssen warten, bis der erste Thread seinen Zugriff beendet hat (gegenseitiger Ausschluß, mutual exclusion). Die Sprache Java stellt hierfür Sprachmittel zu Verfügung
◇ Verklemmung (deadlock) Wenn zwei (oder mehr) Threads wechselseitig auf Daten (allgemeiner : Betriebsmittel) zugreifen wollen, die der jeweils andere Thread – infolge von Synchronisationsmassnahmen – exklusiv belegt hat, blockieren sie sich gegenseitig. Diese Situation kann z.B. auftreten, wenn Thread A die Zugriffsberechtigung zu einem Objekt X und Thread B die Zugriffsberechtigung zu einem Objekt Y besitzen und beide zu ihrer – zur Freigabe dieser Objekte führenden – Wei- terarbeit den Zugriff auf das jeweils andere Objekt benötigen. Zur Lösung derartiger Probleme existieren in der Sprache Java keine Möglichkeiten. Sie müssen durch wachsame und geschickte Programmierung vermieden werden. •••• Synchronisation in Java : Monitore und Locks
◇ Ein Code-Bereich , in dem ein konkurierender Datenzugriff erfolgen kann, wird als kritischer Abschnitt oder kritische Region bezeichnet. Solange ein Thread einen derartigen kritischen Abschnitt durchläuft, sollte kein anderer Thread in denselben oder einen anderen kritischen Abschnitt, der sich auf dieselben Daten bezieht, eintreten. Durch Überwachung (Freigabe, Sperren) der zu bestimmten Daten (z.B. einem Objekt) gehörenden kritischen Abschnit- te lässt sich der Zugriff zu diesen Daten synchronisieren.
◇ Zur Überwachung der kritischen Abschnitte werden in Java sogenannte Monitore eingesetzt. Ein Monitor stellt sicher, dass immer nur der Thread, der die Zugriffsberechtigung zu den jeweiligen Daten besitzt, den durch ihn geschützten Code ausführen kann.
◇ In Java ist mit jedem Objekt ein Monitor assoziiert, der nach entsprechender Aktivierung den Zugriff zu dem Objekt überwacht. Die Aktivierung des Monitors bezieht sich immer auf einen bestimmten überwachten Codeabschnitt. Monitore werden mittels Locks (Zugriffssperren) verwaltet. Ein Thread kann einen Monitor belegen, in dem er einen Lock auf den Monitor setzt ("lock the monitor"). Solange der Thread den Lock auf den Monitor besitzt, kann er uneingeschränkt zu dem von dem Monitor überwachten Objekt zugreifen. Versucht ein anderer Thread einen Lock auf denselben Monitor (d.h. einen Zugriff auf dasselbe Objekt) zu erlangen, muß er warten, bis der erste Thread den Lock wieder freigegeben hat ("unlock the monitor"). Erst dann kann er seiner- seits den Lock setzen und danach zu dem Objekt zugreifen. Versucht ein Thread einen durch einen aktivierten Monitor überwachten Codeabschnitt auszuführen, überprüft der Monitor, ob der Thread den benötigten Lock setzen darf. Wenn ja, darf er in den Codeabschnitt eintreten, wenn nein, muß er warten bis der Lock freigegeben wird.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 732 – 00 – TH – 01 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (2) •••• Demonstrationsprogramm zum Zugriffs-Wettlauf bei Multithreading
◇ Quellcode der Klasse LValBox (Datei LValBox.java)
◇ Quellcode der Klasse LVBChangeThread (Datei LVBChangeThread.java)
◇ Beispiel für Start und Ausgabe des Programms
public class LValBox { private long val; public LValBox(long lv) { val=lv; } public long getVal() { return val; } public void setVal(long lv) { val=lv; } }
// LVBChangeThread.java public class LVBChangeThread extends Thread { private LValBox vbox; public LVBChangeThread(LValBox vb) { vbox=vb; } public void run() { long val = 0; for (int i=0; i<1000; i++) { val=vbox.getVal(); val++; int s=0; while (s<200000) s+=1; // nur zum Zeitverbrauch vbox.setVal(val); } } public static void main(String[] args) { LValBox vbox = new LValBox(0); LVBChangeThread t1 = new LVBChangeThread(vbox); LVBChangeThread t2 = new LVBChangeThread(vbox); t1.start(); t2.start(); while (t1.isAlive() || t2.isAlive()); System.out.println("letzter Wert : " + vbox.getVal()); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 733 – 00 – TH – 05 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (3) •••• Die synchronized-Anweisung
◇ Diese Anweisung dient zum Aktivieren des Monitors, mit dem der Zugriff zu einem Objekt (Ziel-Objekt) synchroni- siert werden kann. Sie legt das betreffende Ziel-Objekt fest und definiert die der Überwachung unterliegende Anweisungsfolge
◇ Syntax : Der in runden Klammern stehende Ausdruck muß als Wert eine Referenz auf ein Objekt ergeben. Er bestimmt das Objekt, zu dem der Zugriff synchronisiert werden soll (Ziel-Objekt). Die in geschweiften Klammern stehende Anweisungsfolge (der "Rumpf" derAnweisung) bildet den überwachten kritischen Codeabschnitt, in dem i.a. (aber nicht immer) zu dem Zielobjekt zugegriffen werden sollte.
◇ Beispiel :
◇ Wirkung :
▻ Die synchronized-Anweisung überprüft, ob der aufrufende Thread den Lock auf den Monitor des durch den Ausdruck referierten Objekts, das Ziel-Objekt, (im Beispiel : vbox) setzen kann (oder bereits besitzt).
▻ Wenn ja, wird der Lock durch den Thread gesetzt und die im Rumpf stehende Anweisungsfolge ausgeführt. Nach Beendigung der Anweisungsfolge (entweder normal oder durch das Werfen einer nicht gefangenen Exception) wird der Lock wieder freigegeben.
▻ Wenn nein, besitzt ein anderer Thread bereits den Lock. In dem Fall muß der aufrufende Thread warten, bis der Lock von dem besitzenden Thread wieder frei gegeben wird. Erst dann kann die Anweisung wie oben skizziert weiter ausgeführt werden.
◇ Weitere Anmerkungen
▻ Die synchronized-Anweisung bewirkt, dass das Setzen und Freigeben eines Locks immer als Paar auftritt. Dadurch ist es nicht möglich, dass ein von einem Thread gehaltener Lock von diesem nicht wieder freigegeben wird (ausser im Fall einer Verklemmung)
▻ Der Zugriff eines Threads zu einem Objekt, auf dessen Monitor ein anderer Thread den Lock besitzt, ohne Aktivie- rung der Monitor-Überwachung (d.h. ohne entsprechende synchronized-Anweisung) ist grundsätzlich möglich. In diesem Fall findet keine Synchronisation statt.
▻ Die synchronized-Anweisung erlaubt die Festlegung eines beliebigen Objekts als Ziel-Objekt. Wird sie in dem Code, der das Ziel-Objekt verwendet, eingesetzt, spricht man von client-seitiger Synchronisation. Damit die Synchronisation tatsächlich funktionieren kann, muß hierbei jeder das Objekt benutzende Client einen synchronisierten Zugriff sicherstellen. Sie kann aber auch in den Memberfunktionen des Ziel-Objekts selbst eingesetzt werden. In diesem Fall muss das Ziel-Objekt durch this referiert werden. Das Ziel-Objekt sorgt selbst für seine Zugriffs-Synchronisation. Eine unsynchronisierte Verwendung durch Clients ist nicht möglich. Manchmal wird dies als server-seitige Synchronisation bezeichnet.
▻ Da Synchronisation i.a. zu einem Performenz-Verlust führen kann (Threads müssen auf Zugriff warten), sollte ein Monitor-Lock immer nur so kurz wie möglich besessen werden, d.h. der überwachte Codeabschnitt sollte auf die unbedingt notwendigen Anweisungen beschränkt werden.
Anweisung { } synchronized ( ) Ausdruck
synchronized (vbox) {
val=vbox.getVal(); val++; vbox.setVal(val); }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 734 – 00 – TH – 01 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (4) •••• Demonstrationsprogramm zur synchronized-Anweisung (client-seitige Synchronisation)
◇ Quellcode der Klasse LValBox (Datei LValBox.java)
◇ Quellcode der Klasse LVBChangeThreadSync (Datei LVBChangeThreadSync.java)
◇ Beispiel für Start und Ausgabe des Programms
public class LValBox { private long val; public LValBox(long lv) { val=lv; } public long getVal() { return val; } public void setVal(long lv) { val=lv; } }
// LVBChangeThreadSync.java public class LVBChangeThreadSync extends Thread { private LValBox vbox; public LVBChangeThreadSync(LValBox vb) { vbox=vb; } public void run() { long val = 0; for (int i=0; i<1000; i++) { synchronized (vbox) { val=vbox.getVal(); val++; int s=0; while (s<200000) s+=1; // nur zum Zeitverbrauch vbox.setVal(val); } } } public static void main(String[] args) { LValBox vbox = new LValBox(0); LVBChangeThreadSync t1 = new LVBChangeThreadSync(vbox); LVBChangeThreadSync t2 = new LVBChangeThreadSync(vbox); t1.start(); t2.start(); while (t1.isAlive() || t2.isAlive()); System.out.println("letzter Wert : " + vbox.getVal()); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 735 – 00 – TH – 02 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (5) •••• synchronized-Methoden
◇ Sowohl statische als auch nichtstatische Memberfunktionen können mit dem Methoden-Modifizierer synchronized definiert werden.
◇ Hierdurch wird ein Monitor für die gesamte Memberfunktion aktiviert. Die gesamte Memberfunktion unterliegt damit einer Synchronisations-Überwachung.
◇ Bei nichtstatischen Memberfunktionen ist das Ziel-Objekt, für das der Monitor aktiviert wird, das jeweils aktuelle Objekt, für das die Memberfunktion aufgerufen wird. Damit stellt die Modifizierung einer nichtstatischen Memberfunktion mit synchronized eine abkürzende Schreib- weise für eine "normale" Memberfunktion dar, bei der der gesamte Funktionsrumpf in eine synchronized-Anwei- sung mit der Ziel-Objekt-Referenz this eingeschlossen ist. Die beiden folgenden Formulierungen sind in ihrer Wirkung identisch :
◇ Bei statischen Memberfunktionen ist das Ziel-Objekt das Class-Objekt, das mit der Klasse der Memberfunktion assoziiert ist. Auch hier gilt, dass die Modifizierung der Memberfunktion mit synchronized eine abkürzende Schreibweise dar- stellt für eine nicht-modifizierte Memberfunktion, bei der der gesamte Funktionsrumpf in eine synchronized-An- weisung gekapselt ist. Wenn der Name der Klasse, zu der die statische Memberfunktion gehört, MyClass ist, lautet die Referenz auf das Ziel-Objekt hier MyClass.class (ein derartiger Ausdruck wird class literal genannt) Statische synchronized-Methoden können lediglich den Zugriff zu statischen Datenkomponenten der Klasse synchronisieren.
◇ Der durch den Aufruf einer statischen synchronized-Methode erlangte Besitz eines Monitor-Locks für das Class-Objekt einer Klasse hat keinen Einfluß auf den Zugriff zu irgendwelchen Objekten dieser Klasse. Ein Thread kann also durchaus nichtstatische synchronized-Methoden für ein Objekt einer Klasse aufrufen, während ein anderer Thread einen durch eine statische Methode erworbenen Lock für das Class-Objekt dieser Klasse besitzt.
◇ Die Definition von synchronized-Methoden implementiert immer eine serverseitige Synchronisation. Clients können also das Einrichten von Monitoren nicht "vergessen". Andererseits unterliegen hierbei immer vollständige Methoden der Synchronisations-Überwachung. Gegebenenfalls kann es effizienter sein, nur für die wirklich notwendigen Teile einer Methode eine entsprechende Über- wachung vorzusehen. Hierfür müssen dann entsprechende synchronized-Anweisungen eingesetzt werden. Ausserdem ist serverseitige Synchronisation nicht immer möglich. So lassen sich read-modify-write-Zugriffe durch einen Client i.a. nicht als Memberfunktion des Server-Objekts formulieren (Server-Objekt kennt Art des modify nicht) •••• Wirksamkeit der Synchronisation mittels synchronized-Anweisungen und -Methoden
◇ Die durch synchronized-Anweisungen und –Methoden implementierte Synchronisation löst direkt nur das Problem der inkonsistenten und fehlerhaften Daten bei nebenläufigem Lesen und Schreiben (Leser-Schreiber-Problem) (Sperrsynchronisation, gegenseitiger Ausschluß, mutual exclusion)
◇ Das zu zeitabhängigen Ergebnissen führende Problem der gegenseitigen Datenabhängigkeit von Threads (Produzenten- Verbraucher-Problem, Reihenfolge des Zugriffs ist wichtig) lässt sich damit aber nicht ausreichend lösen. Hierfür muß die Sperrsynchronisation um zusätzliche Mechanismen ergänzt werden (� Zustands- bzw Ereignis-Synchronisation). Derartige Mechanismen werden z.B. durch Synchronisations-Methoden der Klasse Object zur Verfügung gestellt
public synchronized void myFunc() { // tue etwas }
public void myFunc() { synchronized (this) { // tue etwas } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 736 – 00 – TH – 02 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (6) •••• Die Methoden wait() und notify() der Klasse Object
◇ Neben einem Monitor ist jedem Objekt in Java auch eine Warteliste (wait set) zugeordnet. In diese Warteliste werden Threads eingetragen, die vom Scheduler unterbrochen worden sind und zu ihrer Fortsetzung auf den Eintritt eines Ereignisses warten. Nach der Erzeugung eines Objekts ist diese Warteliste leer.
◇ Die in der Klasse Object definierten – nicht überschreibbaren – Methoden wait() und notify() interagieren mit dem Scheduler und arbeiten mit der Warteliste des Objekts, für das sie jeweils aufgerufen werden. Sie stellen einen weiteren Mechanismus zur Synchronisation von Threads zur Verfügung, der das Monitor-Konzept ergänzt.
◇ Sowohl wait() als auch notify() dürfen nur für ein Objekt aufgerufen werden, dessen Monitor-Lock von dem jeweiligen aktuellen Thread besessen wird, d.h. sie dürfen nur innerhalb von synchronized-Code verwendet werden.
◇ Ein Aufruf von wait() bewirkt, dass der aktuelle Thread angehalten, der von ihm besessene Lock auf den Monitor des Ziel-Objekts freigegeben und der Thread in die Thread-Warteliste des Ziel-Objekts eingetragen wird. Für den Scheduler wird dieser Thread als – auf ein Ereignis – wartend markiert. Ein anderer – eventuell schon darauf wartender – Thread kann damit den Lock auf den Monitor des Objekts bekommen.
◇ Ein Aufruf von notify() kennzeichnet den Eintritt des Ereignisses, auf das die in der Warteliste eingetragenen Threads warten. Er bewirkt, dass einer dieser Threads (oder auch alle) aufgeweckt, d.h. als ablaufbereit markiert wird. Damit kann dieser dann vom Scheduler wieder für die CPU-Zuteilung berücksichtigt werden. Wird er als nächster laufender Thread ausgewählt, bekommt er den Lock auf den Monitor des Objekts wieder zurück. Allerdings ist das erst dann möglich, wenn der Thread, der notify() aufgerufen hat, den Lock auf den Monitor des Objekts seinerseits wieder freigegeben hat. Der Weiterlauf des wartenden Threads führt zur Beendigung der von ihm aufgerufenen wait()-Methode.
◇ Es gibt Varianten der wait()-Methode, mit der der aufrufende Thread ein Timeout-Interval festlegen kann, nachdem er spätestens aufgeweckt werden möchte, auch dann, wenn bis dahin kein notify()-Aufruf für das Objekt erfolgt ist.
◇ wait()-Methoden Jede der wait()-Methoden kann eine InterruptedException werfen, die gefangen werden muß. Diese Exception wird geworfen, wenn ein anderer Thread für den wartenden Thread interrupt() aufruft
◇ notify()-Methoden
public final void wait() Veranlasst, dass der aktuelle Thread in den Wartezustand übergeht bis ein anderer Thread notify() oder notifyAll() für dasselbe Ziel-Objekt aufruft. Der aktuelle Thread muss den Lock für dieses Objekt besitzen. Der Lock wird für die Dauer des Wartezustands abgegeben
public final void wait(long timeout) wie wait(), jedoch wird der Wartezustand spätestens nach Ablauf von timeout Millisek verlassen
public final void wait(long timeout, wie wait(), jedoch wird der Wartezustand spätestens nach int nanos) Ablauf von (timeout Millisek + nanos Nanosek) verlassen
public final void notify() Weckt einen der Threads aus der Thread-Warteliste des Ziel-Objekts auf Welcher Thread aufgeweckt wird, kann nicht vorausgesagt werden
public final void notifyAll() Weckt alle Threads aus der Thread-Warteliste des Ziel-Objekts auf
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 737 – 00 – TH – 03 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (7) •••• Ereignissynchronisation mittels wait() und notify()
◇ Unter Ereignis- oder Zustands-Synchronisation versteht man die Sicherstellung einer definierten zeitlichen Reihen- folge bei der Abarbeitung von mehreren Threads. Die Reihenfolge wird durch den Eintritt bestimmter Ereignisse (bzw bestimmter Zustände) gesteuert. Ein wartender Thread muss von einem anderen Thread über den Eintritt eines erwarteten Ereignisses informiert werden � Zwischen Threads muß eine elementare Kommunikation stattfinden.
◇ Eine definierte Abarbeitungs-Reihenfolge von Threads ist immer dann notwendig, wenn diese voneinander datenab- hängig sind. Ein typisches Beispiel hierfür ist die Erzeugung von Daten durch einen Thread und deren Verwendung durch einen anderen Thread. � Erzeuger-Verbraucher-Problem.
◇ Die Object-Methoden wait() und notify() ermöglichen die für eine Ereignissynchronisation notwendige elementare Thread-Kommunikation. Ein Thread wartet bis ein bestimmtes Ereignis eintritt, das eine von ihm zu überprüfende Bedingung beeinflusst haben könnte. Mittels notify() wird er von einem anderen Thread über den Eintritt dieses Ereignisse informiert.
◇ Der Code zur Realisierung einer Ereignissynchronisation kann sowohl in dem Objekt, auf das der Monitor-Lock bestehen muß (serverseitige Sync.) als auch in einem anderen Objekt (z.B. im Thread-Objekt, clientseitige Sync.) enthalten sein.
◇ Typische prinzipielle Formulierung des Synchronisations-Codes :
▻ im wartenden (empfangenden) Thread (hier in einer Methode des Objekts auf das der Thread den Lock besitzt, serverseitige Synchronisation) Anmerkung : Die Überprüfung der Bedingung, die über Warten oder Weiterarbeit entscheidet, sollte unbedingt in einer Schleifenanweisung und nicht in einer if-Anweisung erfolgen. Nur dann kann der Thread nach Beendigung der wait()-Anweisung auch überprüfen, ob die erwartete Bedingung jetzt tatsächlich erfüllt ist. Sollte dies nicht der Fall sein, geht der Thread mit einem erneuten wait()-Aufruf sofort wieder in den Wartezustand über.
▻ im aufweckenden (sendenden) Thread (hier in einer Methode des Objekts auf das der Thread den Lock besitzt, serverseitige Synchronisation)
•••• Unterbrechung von Threads mittels wait() und notify()
◇ Die Methoden wait() und notify() können auch zur Unterbrechungssteuerung eines typischerweise in einer Schleife laufenden Threads eingesetzt werden.
◇ Dabei legt der Wert einer logischen Variablen fest, ob der gesteuerte Thread unterbrochen werden oder weiterlaufen soll. Der gesteuerte Thread überprüft bei jedem Schleifendurchlauf diese Variable. Hat sie den Wert für "unterbrechen" legt sich der Thread durch den Aufruf von wait() "schlafen". Der steuernde Thread ändert den Wert dieser Variablen und informiert den zu steuernden Thread mittels notify() wenn sie den Wert für "weiterlaufen" angenommen hat. Dadurch wird dieser wieder aufgeweckt und kann weiterlaufen.
synchronized void doSomething() { while (!bedingung) wait(); // Weiterarbeit }
synchronized void changeCondition() { // tue etwas, das bedingung veraendert notifyAll() // oder : notify() }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 738 – 01 – TH – 03 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (8-1) •••• Demonstrationsprogramm zum Erzeuger-Verbraucher-Problem
◇ Ein Erzeuger-Thread erzeugt laufend einen zwischen 0 und 1000 liegenden int-Wert und legt diesen in einem Buffer ab. Ein Verbraucher-Thread soll den im Buffer befindlichen int-Wert jeweils wieder auslesen.
◇ Quellcode des Interfaces IntBuffer (Datei IntBuffer.java)
◇ Quellcode der Klasse IntErzeuger (Datei IntErzeuger.java)
◇ Quellcode der Klasse IntVerbraucher (Datei IntVerbraucher.java)
public interface IntBuffer { public void put(int val); public int get(); public int getBuffSize(); }
public class IntErzeuger extends Thread { private IntBuffer buff; private int cnt; // Anz. der zu erzeugenden Bufferfuellungen public IntErzeuger(IntBuffer b, int anz) { buff = b; cnt = anz; } public void run() { int val; int wdh=cnt*buff.getBuffSize(); for (int i=0; i<wdh || cnt==0; i++) { val = (int)(Math.random()*1000); buff.put(val); System.out.println("erzeugt : " + val); try { Thread.sleep((int)(Math.random()*200)); } catch(InterruptedException e) {} }
} }
public class IntVerbraucher extends Thread { private IntBuffer buff; private int cnt; // Anz. der zu verbrauchenden Bufferfuellungen public IntVerbraucher(IntBuffer b, int anz) { buff = b; cnt = anz; } public void run() { int val; int wdh=cnt*buff.getBuffSize(); for (int i=0; i<wdh || cnt==0 ; i++)
{ val = buff.get(); System.out.println(" verbraucht : " + val); try { Thread.sleep((int)(Math.random()*200)); } catch(InterruptedException e) {} } } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 738 – 02 – TH – 03 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (8-2) •••• Demonstrationsprogramm zum Erzeuger-Verbraucher-Problem, Forts.
◇ Ohne Ereignissynchronisation : Quellcode der Klasse UnsyncIntBuffer (Datei UnsyncIntBuffer.java)
◇ Beispiel für Start und Ausgabe des Programms
// UnsyncIntBuffer.java public class UnsyncIntBuffer implements IntBuffer { private int buff; public synchronized void put(int val) { buff= val; } public synchronized int get() { int val = buff; return val; } public int getBuffSize() { return 1; } public static void main(String[] args) { IntBuffer ibuff = new UnsyncIntBuffer(); new IntErzeuger(ibuff, 8).start(); new IntVerbraucher(ibuff, 8).start(); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 738 – 03 – TH – 03 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (8-3) •••• Demonstrationsprogramm zum Erzeuger-Verbraucher-Problem, Forts.
◇ Mit Ereignissynchronisation : Quellcode der Klasse SyncIntBuffer (Datei SyncIntBuffer.java)
◇ Beispiel für Start und Ausgabe des Programms
public class SyncIntBuffer implements IntBuffer { private int buff; private boolean voll; public SyncIntBuffer() { voll = false; } public synchronized void put(int val) { while (voll) { try
{ wait(); }
catch (InterruptedException e) { }
}
buff = val; voll = true; notifyAll(); // Mitteilung, dass Buffer voll ist
} public synchronized int get() { while (!voll) { try
{ wait(); }
catch (InterruptedException e) { }
}
int val = buff; voll = false; notifyAll(); // Mitteilung, dass Buffer leer ist return val; } public int getBuffSize() { return 1; } public static void main(String[] args) { IntBuffer ibuff = new SyncIntBuffer(); new IntErzeuger(ibuff, 8).start(); new IntVerbraucher(ibuff, 8).start(); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 739 – 01 – TH – 01 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (9-1) •••• Demonstrationsprogramm zum Unterbrechen/Weiterlaufen von Threads, Teil 1
◇ Quellcode der Klasse BlinkDemo2 (Datei BlinkDemo2.java)
◇ Vom Programm erzeugtes Fenster (beide Blinkzustände)
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class BlinkDemo2 extends JFrame { Container c; BlinkPanel blkpan; BlinkThread2 blkthr = null; public BlinkDemo2() { super("BlinkDemo2"); c=getContentPane(); blkpan = new BlinkPanel(Color.YELLOW, Color.BLUE); c.add(blkpan); setSize(250, 170); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); blkpan.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { System.out.println(Thread.currentThread()); if (blkthr==null) { blkthr = new BlinkThread2(BlinkDemo2.this); blkthr.start(); } else synchronized(blkthr) { blkthr.toggleBreak();
blkthr.notify();
}
} } ); } public void blink() { blkpan.chgCol(); repaint(); } public static void main(String[] args) { BlinkDemo2 blkdemo = new BlinkDemo2(); blkdemo.setVisible(true); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK BEREICH DATENTECHNIK V – JV – 739 – 02 – TH – 01 -----------------------------------------------------------------------------------
Synchronisation von Threads in Java (9-2) •••• Demonstrationsprogramm zum Unterbrechen/Weiterlaufen von Threads, Teil2
◇ Quellcode der Klasse BlinkPanel (Datei BlinkPanel.java) s. Demonstrationsprogramm zum gezielten vorzeitigen Beenden eines Threads (V-JV-722-02)
◇ Quellcode der Klasse BlinkThread2 (Datei BlinkThread2.java)
// BlinkThread2.java public class BlinkThread2 extends Thread { private BlinkDemo2 blkdem; private boolean unterbrechung;
public BlinkThread2(BlinkDemo2 bd) { blkdem=bd; unterbrechung=false; } public void toggleBreak()
{
unterbrechung = !unterbrechung;
} public void run() { System.out.println(Thread.currentThread() + " Begin"); System.out.println("Anz. aktiver Threads : " + Thread.activeCount()); while (true) { try { synchronized (this) { while(unterbrechung) wait();
} blkdem.blink(); Thread.sleep(500); } catch (InterruptedException e) { break;} } System.out.println(Thread.currentThread() + " Ende"); } }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 741 – 00 – TH – 03 -----------------------------------------------------------------------------------
Thread-Kommunikation über Pipes in Java (1)
•••• Pipes
◇ Eine Pipe ist ein unidirektionaler Kommunikationskanal, über den zwei Prozesse bzw Threads gekoppelt werden können : Eine Pipe besitzt eine Schreibseite und eine Leseseite. Ein Prozess/Thread ist mit der Schreibseite verbunden und schreibt Daten in die Pipe, der andere Prozess/Thread ist mit der Leseseite verbunden und liest die geschriebenen Daten in genau der gleichen Reihenfolge wieder aus.
◇ Pipes sind spezielle Streams. Sie werden also dateiähnlich verwendet, mit der Besonderheit, dass zur Schreibseite einer Pipe nur schreibend und zur Leseseite nur lesend zugegriffen werden kann.
◇ Pipes werden mittels eines im Arbeitsspeicher angelegten Puffers implementiert. Wenn der Puffer voll ist, blockiert der schreibende Prozess/Thread , wenn der Puffer leer ist blockiert der lesende Prozess/Thread. � Pipes stellen einen Synchronisationsmechanismus zur Verfügung, mit dem sich das Erzeuger-/Verbraucher- Problem sehr effizient lösen lässt. •••• Pipes in Java
◇ In Java lassen sich Pipes sowohl als Byte-Streams als auch als Zeichen-Streams realisieren. Hierfür existieren – im Package java.io – die Klassen
▻ PipedOutputStream (abgeleitet von OutputStream) und PipedInputStream (abgeleitet von InputStream) (Byte-Streams), sowie
▻ PipedWriter (abgeleitet von Writer) und PipedReader (abgeleitet von Reader) (Zeichen-Streams).
◇ Objekte der Klasse PipedOutputStream bilden die Schreibseite, Objekte der Klasse PipedInputStream bilden die Leseseite einer Pipe. Sie werden immer paarweise und immer in verschiedenen Threads eingesetzt. Analoges gilt für Objekte der Klassen PipedWriter und PipedReader.
◇ Klassendiagramme
◇ Die Kopplung zwischen je einem PipedOutputStream- und einem PipedInputStream-Objekt (bzw einem PipedWriter- und einem PipedReader-Objekt) kann gleich bei der Objekterzeugung (Konstruktor-Parameter) oder später mittels einer geeigneten Memberfunktion erfolgen. Dabei ist es gleichgültig, ob ein PipedInputStream-Objekt an ein PipedOutputStream-Objekt (bzw ein PipedReader-Objekt an ein PipedWriter-Objekt) gekoppelt wird oder umgekehrt. Wenn bereits eine Kopplung besteht, führt der Versuch einer erneuten Kopplung zum Werfen einer IOException.
◇ Der für eine Pipe verwendete Puffer umfasst 1024 Bytes. Diese Größe kann nicht verändert werden.
◇ Der Versuch der Verwendung (Schreiben bzw Lesen) eines Pipe-Stream-Objekts, das nicht an eine Gegenseite gekoppelt ist, führt zum Werfen einer IOException. Dies ist z.B. auch dann der Fall, wenn der Thread der Gegenseite zwischenzeitlich beendet worden ist.
OutputStream
PipedOutputStream
InputStream
PipedInputStream 1 1
Writer
PipedWriter 1 1
Reader
PipedReader
Byte-Stream-Pipe Zeichen-Stream-Pipe
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 742 – 00 – TH – 03 -----------------------------------------------------------------------------------
Thread-Kommunikation über Pipes in Java (2) •••• Die Klasse PipedOutputStream (Package java.io)
◇ Objekte dieser Klasse bilden die Schreibseite einer Byte-Stream-Pipe.
◇ Konstruktoren
◇ Memberfunktionen Die Klasse PipedOutputStream stellt das durch ihre Basisklasse OutputStream definierte Zugriffs- Interface zur Verfügung Zusätzlich ist definiert : Alle Methoden werfen eine IOException, wenn ein I/O-Fehler auftritt (z.B: Schreibversuch bei fehlender Pipe- Kopplung)
•••• Die Klasse PipedWriter (Package java.io)
◇ Objekte dieser Klasse bilden die Schreibseite einer Zeichen-Stream-Pipe.
◇ Es existieren
▻ analoge Konstruktoren (Default-Konstruktor und Konstruktor zur Kopplung an einPipedReader-Objekt) und
▻ analoge Memberfunktionen (Interface der Basisklasse Writer, sowie Methode connect(...)) wie bei der Klasse PipedOutputStream.
public PipedOutputStream() Erzeugung eines PipedOutputStream- Objekts, das an kein PipedInputStream- Objekt (Pipe-Leseseite) gekoppelt ist
public PipedOutputStream(PipedInputStream snk) Erzeugung eines PipedOutputStream- throws IOException Objekts, das an das PipedInputStream- Objekt snk (Pipe-Leseseite) gekoppelt ist.
public void connect(PipedInputStream snk) Kopplung des aktuellen Objekts an das PipedInputStream-Objekt snk (Pipe-Leseseite)
public void write(int b) Schreiben des niederwertigen Bytes von b
public void write(byte[] buff) Schreiben des Byte-Buffers buff
public void write(byte[] buff, int pos, Schreiben von len Bytes aus dem Buffer buff ab int len) der Position pos
public void flush() Übergabe aller gepufferten Schreib-Bytes an den Pipe-Buffer
public void close() Schliessen des Streams (Pipe-Schreibseite)
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 743 – 00 – TH – 03 -----------------------------------------------------------------------------------
Thread-Kommunikation über Pipes in Java (3) •••• Die Klasse PipedInputStream (Package java.io)
◇ Objekte dieser Klasse bilden die Leseseite einer Byte-Stream-Pipe.
◇ Konstruktoren
◇ Memberfunktionen Die Klasse PipedInputStream stellt das durch ihre Basisklasse InputStream definierte Zugriffs- Interface zur Verfügung. Allerdings werden die Methoden mark(...) und reset() nicht unterstützt. Zusätzlich ist u.a. definiert : Alle Methoden werfen eine IOException, wenn ein I/O-Fehler auftritt (z.B: Leseversuch bei fehlender Pipe- Kopplung) •••• Die Klasse PipedReader (Package java.io)
◇ Objekte dieser Klasse bilden die Leseseite einer Zeichen-Stream-Pipe.
◇ Es existieren
▻ analoge Konstruktoren (Default-Konstruktor und Konstruktor zur Kopplung an einPipedWriter-Objekt) und
▻ analoge Memberfunktionen (Interface der Basisklasse Reader, sowie Methode connect(...)) wie bei der Klasse PipedInputStream.
public PipedInputStream() Erzeugung eines PipedInputStream- Objekts, das an kein PipedOutputStream- Objekt (Pipe-Schreibseite) gekoppelt ist
public PipedInputStream(PipedOutputStream src) Erzeugung eines PipedInputStream- throws IOException Objekts, das an das PipedOutputStream- Objekt src (Pipe-Schreibseite) gekoppelt ist.
public void connect(PipedOutputStream src) Kopplung des aktuellen Objekts an das PipedOutputStream-Objekt src (Pipe-Schreibs.)
public int read() Lesen des nächsten Bytes aus der Pipe (==Funktionswert) Funktionswert==-1, wenn Schreibseite geschlossen
public int read(byte[] buff) Lesen einer Byte-Folge, Ablage im Buffer buff Funktionswert : Anz. gelesener Bytes bzw –1, wenn Schreibseite geschlossen
public int read(byte[] buff, int pos, Lesen von maximal len Bytes, Ablage imBuffer buff int len) ab der Position pos Funktionswert : Anz. gelesener Bytes, bzw –1 (wie oben)
public int available() Ermittlung der Anzahl Bytes, die in der Pipe verfügbar sind, d.h. ohne Blockierung gelesen werden können
public long skip(long n) Überlesen der nächsten (maximal) n Bytes Funktionswert : Anzahl der tatsächlich überlesenen Bytes
public void close() Schliessen des Streams (Pipe-Leseseite)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 744 – 01 – TH – 01 -----------------------------------------------------------------------------------
Thread-Kommunikation über Pipes in Java (4-1)
•••• Demonstrationsprogramm zur Lösung des Erzeuger-Verbraucher-Problems mittels Pipes
◇ Ein Erzeuger-Thread erzeugt laufend einen zwischen 0 und 1000 liegenden int-Wert und schreibt diesen in eine Pipe. Ein Verbraucher-Thread liest die erzeugten Werte aus der Pipe.
◇ Zur vereinfachten Übertragung der int-Werte in Binärdarstellung werden der Pipe Filter vor- bzw nachgeschaltet :
▻ der Pipe-Schreibseite (PipedOutputStream-Objekt) wird ein DataOutputStream-Objekt vorgeschaltet
▻ der Pipe-Leseseite (PipedInputStream-Objekt) wird ein DataInputStream-Objekt nachgeschaltet
◇ Quellcode der Klasse IntErzeugerPiped (Datei IntErzeugerPiped.java)
// IntErzeugerPiped.java import java.io.*; public class IntErzeugerPiped extends Thread { private PipedOutputStream outpipe; private int cnt; public IntErzeugerPiped(PipedOutputStream op, int anz) { outpipe = op; cnt = anz; } public void run() { try { DataOutputStream pout = null; try { int val; pout = new DataOutputStream(outpipe); for (int i=0; i<cnt; i++) { val = (int)(Math.random()*1000); pout.writeInt(val); System.out.println("erzeugt : " + val); try { Thread.sleep((int)(Math.random()*200)); } catch(InterruptedException e) {} } } finally { pout.close(); } } catch(IOException ex) { System.err.println(ex.getMessage()); } } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 744 – 02 – TH – 02 -----------------------------------------------------------------------------------
Thread-Kommunikation über Pipes in Java (4-2)
•••• Demonstrationsprogramm zur Lösung des Erzeuger-Verbraucher-Problems mittels Pipes, Forts.
◇ Quellcode der Klasse IntVerbraucherPiped (Datei IntVerbraucherPiped.java)
// IntVerbraucherPiped.java import java.io.*; public class IntVerbraucherPiped extends Thread { private PipedInputStream inpipe; private int cnt; public IntVerbraucherPiped(PipedInputStream ip, int anz) { inpipe = ip; cnt = anz; } public void run() { try { int val; DataInputStream pin = new DataInputStream(inpipe); for (int i=0; i<cnt; i++) { val = pin.readInt(); System.out.println(" verbraucht : " + val); try { Thread.sleep((int)(Math.random()*200)); } catch(InterruptedException e) {} } } catch (EOFException ex) { System.out.println(" fertig !!!"); } catch(IOException ex) { System.err.println(ex.getMessage()); } } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 744 – 03 – TH – 02 -----------------------------------------------------------------------------------
Thread-Kommunikation über Pipes in Java (4-3)
•••• Demonstrationsprogramm zur Lösung des Erzeuger-Verbraucher-Problems mittels Pipes, Forts.
◇ Quellcode der Klasse PipeDemo (Datei PipeDemo.java)
◇ Beispiel für Start und Ausgabe des Programms
// PipeDemo.java import java.io.*; public class PipeDemo { public static void main(String[] args) throws IOException { PipedOutputStream opipe = new PipedOutputStream(); PipedInputStream ipipe = new PipedInputStream(opipe); new IntErzeugerPiped(opipe, 12).start(); new IntVerbraucherPiped(ipipe, 13).start(); } }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 800 – 00 – TH – 03 -----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 8
8. Java in verteilten Systemen 8.1. Socket-basierte Kommunikation 8.2. Remote Method Invocation (RMI)
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 801 – 00 – TH – 01 -----------------------------------------------------------------------------------
Grundlegendes zu verteilten Systemen
•••• Verteilte Systeme
◇ Verteilte Systeme bestehen aus zwei oder mehr unabhängigen aber miteinander verbundenen Rechnern (z.B. über ein Netzwerk), die zur gemeinsamen Lösung von Aufgaben eingesetzt werden können.
◇ Die gemeinsam zu lösende Aufgabe wird auf mehrere Prozesse aufgeteilt, die auf unterschiedlichen Rechnern laufen. � Verteilte Anwendung
◇ Die an einer verteilten Anwendung beteiligten Prozesse müssen miteinander Informationen austauschen. Die dafür notwendige Interprozess-Kommunikation über Rechnergrenzen hinweg erfordert die Definition und Einhaltung bestimmter Schnittstellen und Protokolle. Derartige Protokolle können auf unterschiedlichen Ebenen (Schichten) eingesetzt werden. •••• Client-Server-Modell
◇ Am häufigsten arbeiten verteilte Anwendungen nach dem Client-Server-Modell : Ein Server-Prozess stellt Dienstleistungen über eine definierte Schnittstelle zur Verfügung. Diese Dienstleistungen können von Client-Prozessen genutzt werden.
◇ Die Kommunikation zwischen Client und Server folgt dem – asymmetrischen – Request-Response-Prinzip : Ein Client richtet zu einem beliebigen Zeitpunkt – also asynchron – eine Anfrage (request) an den auf Anfragen warten- den Server. Der Server antwortet (response) i.a. innerhalb einer bestimmten Zeit – also synchron – auf diese Anfrage.
◇ Häufig kann ein Server gleichzeitig zu mehreren Clients Kommunikationsbeziehungen unterhalten (Multithread- Server)
◇ Verteilte Anwendungen, bei denen die beteiligten Prozesse sowohl als Server als auch als Client agieren, arbeiten nach dem Peer-to-Peer-Modell
◇ Prinzipiell werden zwei Verbindungsarten einer Rechnergrenzen überschreitenden Interprozess-Kommunikation unterschieden :
▻ verbindungsorientierte Kommunikation : Zwischen Client und Server wird für die Dauer der Kommunikation eine ständige – virtuelle – Verbindung herge- stellt. Diese Verbindung muss aufgebaut werden, bevor die eigentliche Kommunikation stattfinden kann. � Die einzelnen Sendeoperationen benötigen keine expliziten Angaben über die Empfängeradresse.
▻ verbindungslose Kommunikation : Zwischen Client und Server existiert keine ständige Kommunikationsverbindung. Diese wird vielmehr mit jeder einzelnen Sendeoperation neu hergestellt. � Jeder Sendeoperation muss die Adresse des Empfängers explizit mitgegeben werden. •••• Programmierschnittstellen
◇ Die programmtechnische Implementierung von Client-Server-Kommunikationen kann auf unterschiedlichen Schichten erfolgen (OSI-Schichten-Modell der Rechnerkommunikation !)
◇ Am weitesten verbreitet sind heute :
▻ Sockets, Programmierschnittstelle der Transportschicht (bzw Vermittlungsschicht) Sockets definieren den jeweiligen Kommunikations-Endpunkt einer logischen Verbindung zwischen Server und Client. Sie basieren auf dem für die jeweilige Verbindung eingesetzten Kommunikationsprotokoll-Typ und den von diesem verwendeten Adress-Angaben. � Es gibt unterschiedliche Socket-Typen Sockets ermöglichen eine bidirektionale Kommunikation (Senden und Empfangen) mittels I/O-Operationen analog zu Datei- bzw Stream-Zugriffen. Eine Kommunikation über einen Socket kann erst stattfinden, wenn er an eine lokale Adresse gebunden ist
▻ Prozedur-Fernaufrufe (Remote Procedure Calls), Programmierschnittstelle der Anwendungsschicht Sie ermöglichen den Aufruf von Unterprogrammen (Funktionen), die sich in einem anderen Prozessraum be- finden unter Anwendung der gleichen Semantik wie für den Aufruf lokaler Unterprogramme. Die Implementierung dieses Konzepts in Java wird Remote Method Invocation (RMI) genannt. RMI erlaubt den Aufruf von Methoden für Objekte, die sich in einer anderen JVM (i.a. auf einem anderen Rechner) befinden.
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 811 – 00 – TH – 01 -----------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (1) •••• Prinzip der verbindungsorientierten Socket-Kommunikation
◇ Der Server-Prozess erzeugt einen Socket, den er an eine lokale Adresse (Server-Adresse) bindet. Art und Aufbau der Adresse hängen von der für die Kommunikation eingesetzten Protokoll-Familie ab. An diesem Socket wartet der Server auf Verbindungswünsche durch Clients ("Horch"-Socket).
◇ Ein Client-Prozess initiiert eine Verbindung zum Server, in dem er einen Socket erzeugt und über diesen einen Verbindungswunsch an die Server-Adresse sendet.
◇ Falls der Server-Prozess den Verbindungswunsch akzeptiert, erzeugt er einen neuen Socket, über den dann die eigent- liche Kommunikation mit dem Client stattfinden kann ("Kommunikations"-Socket).
◇ Die anschliessende eigentliche Client-Server-Kommunikation erfolgt über die Sockets mittels dateianaloger Schreib- und Lese-Operationen
◇ Die Kommunikation wird beendet, wenn der Client-Socket oder/und der "Kommunikations"-Socket des Servers geschlossen werden.
◇ Ein sequentieller Server kann erst nach Abschluss einer Client-Kommunikation auf weitere Verbindungswünsche warten. Bei einem Multi-Thread-Server findet jede Client-Kommunikation in einem seperaten Thread statt. Ein derartiger Server kann auf weitere Verbindungswünsche unmittelbar nach Erzeugung des Kommunikations-Threads warten
◇ Prinzipieller Ablauf :
Multi-Thread- Server
Verbindungsaufnahme
Kommunikation
Client
Erzeugung eines Sockets Verbindungswunsch an die Server-Adresse
Schreib-Operation Lese-Operation
Schliessen des Sockets
Server
Erzeugung eines "Horch"-Sockets
Bindung an die Server-Adresse
Warten auf Verbindungswünsche
durch Clients
Akzeptieren eines Verbindungswunsches
Erzeugung eines "Kommunikations"-Sockets
Lese-Operation Schreib-Operation
Schliessen des "Kommunikations"-Sockets
sequentieller Server
Multi-Thread- Server
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 812 – 00 – TH – 03 ------------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (2) •••• INET-Sockets
◇ INET-Sockets sind Sockets für die TCP/IP-Protokoll-Familie. Diese Protokoll-Familie hat derzeit für die Rechnerkommunikation die grösste Bedeutung. U.a. wird sie im Internet, aber auch in den meisten lokalen Netzen eingesetzt.
◇ Adressen der TCP/IP-Protokoll-Familie (INET-Adressen) bestehen aus zwei Komponenten :
▻ IP-Adresse : Sie bestimmt den Rechner, auf dem ein Prozess läuft 4 Bytes (IP4-Adresse) bzw 16 Bytes (IP6-Adresse) gross.
▻ Port-Nummer : Sie identifiziert den Prozess (Applikation) auf einem Rechner. 2 Bytes gross : ganze Zahl zwischen 0 und 65535 (0 bis 1023 reserviert für systemnahe Dienste, well-known ports)
◇ Zur besseren Verständlichkeit für den benutzenden Menschen werden IP-Adressen häufig auf Rechner-Namen (host names) abgebildet. Die Umsetzung von Rechner-Namen in IP-Adressen erfolgt u.a. durch Domain Name Server (DNS).
◇ Die beiden wichtigsten Protokolle dieser Protokoll-Familie sind :
▻ TCP (Transmission Control Protocol)
▻ UDP (User Datagram Protocol)
◇ TCP ist ein Protokoll für die verbindungsorientierte Kommunikation. Es arbeitet streambasiert und mit Fehlerkontrolle. Dadurch bietet es Schutz gegen Datenverlust und Übertragungsfehler. Ausserdem stellt es die Beibehaltung der Daten-Reihenfolge sicher (sequencing). � zuverlässiges Protokoll Sockets für dieses Protokoll werden als Stream-Sockets bezeichnet.
◇ UDP ist ein Protokoll für die verbindungslose Kommunikation. Es arbeitet paketbasiert (Übertragung unabhängiger Datenpakete == Datagramme) sowie ohne Fehlerkontrolle und Sequencing. Dadurch sind weder Verlustlosigkeit und Fehlerfreiheit noch die Beibehaltung der Datenreihenfolge sichergestellt. � unzuverlässiges Protokoll. Dafür ist die Übertragungsleistung dieses Protokolls höher. Sockets für dieses Protokoll werden Datagram-Sockets genannt. •••• Unterstützung von INET-Sockets in Java
◇ Die Implementierung von verteilten Anwendungen mittels INET-Sockets werden in Java sehr effizient durch geeignete Klassen der Standard-Bibliothek unterstützt. Die entsprechenden Klassen befinden sich im Package java.net.
◇ Zur Implementierung von Stream-Sockets existieren die Klassen
▻ ServerSocket : Klasse für "Horch"-Sockets in Server-Prozessen
▻ Socket : Klasse für "Kommunikations"-Sockets in Client- und Server-Prozessen
◇ Die Implementierung einer verbindungslosen Kommunikation über Datagram-Sockets ermöglichen die Klassen :
▻ DatagramSocket : Klasse für Datagramm-Sockets
▻ DatagramPacket : Klasse zur Beschreibung der zu übertragenen Datenpakete
◇ Socket-Adressen werden repräsentiert durch
▻ SocketAddress : abstrakte Basisklasse für Socket-Adressen, keine konkrete Protokollbindung
▻ InetSocketAddress : konkrete Klasse für Adressen der TCP/IP-Protokoll-Familie (INET-Adresse)
◇ Zur Repräsentation von IP-Adressen existieren die Klassen :
▻ InetAddress : Darstellung sowohl von IP4-Adressen (4-Bytes) als auch IP6-Adressen (16 Bytes)
▻ Inet4Address : Darstellung von IP4-Adressen (abgeleitet von InetAddress)
▻ Inet6Address : Darstellung von IP6-Adressen (abgeleitet von InetAddress)
◇ Zur Repräsentation von Internet-Resourcen referierenden URLs (Uniform Resource Locator) dient die Klasse
▻ URL
◇ Über die o.a. Klassen hinaus umfasst das Package java.net noch eine Reihe weiterer Klassen.
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 813 – 00 – TH – 03 ------------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (3) •••• Die Klasse InetAddress
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse repräsentieren IP-Adressen Über Variable dieses Typs werden tatsächlich Inet4Address-Objekte (für IP4-Adressen (4-Bytes)) bzw Inet6Address-Objekte (für IP6-Adressen (16 Bytes)) referiert. Die Klasse InetAddress stellt ein gemeinsames Verwendungsinterface für beide Arten von IP-Adressen zur Verfügung
◇ Die Klasse besitzt keine öffentlichen Konstruktoren. Zur Objekterzeugung existieren statische Memberfunktionen. Diesen kann entweder die IP-Adresse (als Byte-Array oder als String in dotted decimal notation) oder (gegebenenfalls und) der Rechnername übergeben werden. Bei alleiniger Übergabe des Rechnernamens wird zur Ermittlung der IP-Adresse die im System installierte Methode zur Namensauflösung (address resolution) verwendet. Ist eine übergebene IP-Adresse dem Format nach ungültig oder schlägt die Namensauflösung fehl wird von den Erzeugungsmethoden eine UnknownHostException (abgeleitet von IOException) geworfen.
◇ Neben der IP-Adresse enthalten InetAddress-Objekte gegebenenfalls auch den zugehörigen Rechnernamen. Dies ist dann der Fall, wenn der Name bei der Objekterzeugung verwendet wurde oder eine inverse Namensauflösung (reverse host name resolution) vorgenommen wurde.
◇ Die Klasse InetAddress verwaltet einen Cache, in dem erfolgreiche und nicht erfolgreiche Namensauflösungen abgelegt werden.
◇ Es existieren u.a. Instanz-Memberfunktionen, die die gespeicherte IP-Adresse bzw den Rechnernamen zurück- liefern.
◇ Statische Memberfunktion der Klasse InetAddress zur Objekterzeugung (Auswahl)
◇ Instanz-Memberfunktion der Klasse InetAddress (Auswahl)
public static Erzeugung eines InetAddress-Objekts (genauer : InetAddress getByAddress(byte[] addr) eines Inet4Address- bzw Inet6Address- throws UnknownHostException Objekts) mit der durch addr gegebenen IP-Adresse. Der Parameter addr muss die Address-Bytes in Network Byte Order (big endian) enthalten
public static Erzeugung eines InetAddress-Objekts (genauer : InetAddress getByName(String host) eines Inet4Address- bzw Inet6Address- throws UnknownHostException Objekts) mit der durch Namensauflösung des Rechner- namens host ermittelten IP-Adresse. Der Parameter host kann auch direkt die IP-Adresse in Stringdarstellung (dotted decimal notation) enthalten In diesem Fall entfällt eine Namensauflösung
public byte[] getAddress() Rückgabe der IP-Adresse als Byte-Array (in Network Byte Order)
public String getHostAddress() Rückgabe der IP-Adresse als String in dotted decimal notation
public String getHostName() Rückgabe des Rechnernamens falls dieser im Objekt gespeichert ist oder durch inverse Namensauflösung ermittelt werden kann. Ist ein Security-Manager installiert, so wird bei erforderlicher inverser Namensauflösung dieser befragt, ob die Operation zulässig ist Ist die inverse Namensauflösung unzulässig oder kann der Rechner- name nicht ermittelt werden, wird die IP-Adresse als String in dotted decimal notation zurückgegeben.
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 814 – 00 – TH – 04 ------------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (4) •••• Die abstrakte Klasse SocketAddress
◇ Enthalten im Package java.net.
◇ Diese Klasse repräsentiert generische – an kein konkretes Protokoll gebundene – Socket-Adressen.
◇ Variable dieses Typs müssen immer Objekte einer konkreten von SocketAddress abgeleiteten Klasse referieren. Objekte einer derartigen Klasse repräsentieren an jeweils ein konkretes Protokoll gebundene Socket-Adressen. Z. Zt. existiert in der Java-Standard-Bibliothek lediglich die abgeleitete Klasse InetSocketAddress (für Adressen der TCP/IP-Protokoll-Familie)
◇ Die Klasse wird u.a. als Typangabe (Parameter- und Rückgabetyp) in Methoden der Klassen Socket und ServerSocket verwendet.
•••• Die Klasse InetSocketAddress
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse repräsentieren Adressen der TCP/IP-Protokoll-Familie (INET-Adressen) � Sie enthalten eine IP-Adresse und eine Port-Nummer.
◇ Bei der Objekterzeugung sind dem Konstruktor die IP-Adresse (als InetAddress-Objekt) und die Port-Nummer zu übergeben. Einem alternativen Konstruktor kann statt der IP-Adresse auch der Rechnername übergeben werden. In diesem Fall wird eine Namensauflösung versucht. Bei Fehlschlag derselben wird der Name im Objekt gespeichert. Das Objekt repräsentiert dann eine nichtaufgelöste Adresse (unresolved address). Diese kann beispielsweise bei Verbindungs- aufnahme über einen Proxy verwendet werden.
◇ Die Klasse InetSocketAddress besitzt Memberfunktionen, mit denen die Komponenten einer von einem Objekt repräsentierten Adresse ermittelt werden können.
◇ Konstruktoren der Klasse InetSocketAddress
◇ Memberfunktionen der Klasse InetSocketAddress (Auswahl)
public InetSocketAddress(InetAddress addr, Erzeugung einer INET-Adresse aus der IP-Adresse int port) addr und der Port-Nr port
public InetSocketAddress(int port) Erzeugung einer INET-Adresse aus der IP-Adresse 0.0.0.0 (wildcard) und der Port-Nr port
public Erzeugung einer INET-Adresse aus der durch InetSocketAddress(String host, int port) Namensauflösung von host ermittelten IP-Adresse und der Port-Nr port
public final InetAddress getAddress() Rückgabe der IP-Adresse (als InetAddress-Objekt)
public final int getPort() Rückgabe der Port-Nummer
public final String getHostName() Rückgabe des Rechnernamens
public final boolean isUnresolved() Überprüfung, ob der Rechnername aufgelöst werden konnte Rückgabe von true, wenn Auflösung nicht möglich war Rückgabe von false, wenn Auflösung möglich war
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 815 – 00 – TH – 01 -----------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (5) •••• Die Klasse Socket
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse implementieren TCP-"Kommunikations-Sockets".
◇ Client-seitige Sockets bauen üblicherweise bei ihrer Erzeugung eine Verbindung zu einem Server auf. Hierfür muss ihrem Konstruktor die IP-Adresse und die Port-Nummer der Server-Applikation übergeben werden. Dadurch werden sie auch automatisch an eine geeignete lokale Adresse gebunden. Falls ein Security-Manager installiert ist, überprüft dieser die Zulässigkeit der gewünschten Verbindung. Bei Unzulässigkeit wird eine SecurityException geworfen. Alternativ kann auch ein unverbundener Socket erzeugt werden (parameterloser Konstruktor). Ein derartiger Socket ist dann auch an keine lokale Adresse gebunden. Ein explizites Binden an eine lokale Adresse ist mit der Memberfunktion bind(...) möglich. Der spätere Aufbau einer Server-Verbindung sowie gegebenenfalls die implizite Bindung an eine lokale Adresse kann mittels der Methode connect(...) erfolgen.
◇ Server-seitige Sockets werden beim Akzeptieren eines Client-Verbindungswunsches durch den "Horch-Socket" erzeugt.
◇ Zur Kommunikation stellen Socket-Objekte jeweils ein InputStream- und ein OutputStream-Objekt zur Verfügung � dateiartige Lese- und Schreib-Operationen.
◇ Nach Beendigung der Kommunikation sollten die Stream-Objekte (zuerst) und das Socket-Objekt geschlossen werden.
◇ Viele Memberfunktionen (und Konstruktoren) der Klasse Socket können Exceptions verschiedenen Typs werfen (s. API-Dokumentation)
◇ Konstruktoren der Klasse Socket (Auswahl)
◇ Memberfunktionen der Klasse Socket (Auswahl)
public Socket() Erzeugung eines unverbundenen Sockets Der Socket ist auch an keine lokale Adresse gebunden
public Socket(String host, int port) Erzeugung eines Sockets, der mit der durch host (Rechner- throws UnknownHostException, name oder IP-Adr. als String) und port definierten Server- IOException Adresse verbunden ist. Der Socket wird an eine geeignete lokale Adresse gebunden
public Socket(InetAddress adr, Erzeugung eines Sockets, der mit der durch adr und int port) und port definierten Server-Adresse verbunden ist throws IOException Der Socket wird an eine geeignete lokale Adresse gebunden
public void bind(SocketAddress adr) Binden des Sockets an die lokale Socket-Adresse adr throws IOException (bei der Adresse muss es sich um eine INET-Adr. handeln)
public void connect(SocketAddress adr) Aufbau einer Verbindung zum Server mit der Adresse adr throws IOException (bei der Adresse muss es sich um eine INET-Adr. handeln)
public InputStream getInputStream() Rückgabe eines InputStream-Objekts, mit dem aus throws IOException dem Socket gelesen (empfangen) werden kann
public OutputStream getOutputStream() Rückgabe eines OutputStream-Objekts, mit dem in throws IOException den Socket geschrieben (gesendet) werden kann
public void close() throws IOException Schliessen des Sockets
Memberfunktionen zum Ermitteln der lokalen sowie der verbundenen (entfernten) Adresse, sowohl als INET-Adresse (SocketAddress-Objekt) als auch getrennt für IP-Adresse und Port-Nr), s. API-Dokumentation
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 816 – 00 – TH – 01 -----------------------------------------------------------------------------------
Socket-basierte Kommunikation in Java (6)
•••• Die Klasse ServerSocket
◇ Enthalten im Package java.net.
◇ Objekte dieser Klasse implementieren TCP-"Horch-Sockets" (Server-Sockets).
◇ Üblicherweise wird ein Server-Socket gleich bei seiner Erzeugung an die lokale Adresse gebunden, an der er auf Verbindungswünsche warten soll. Da die IP-Adresse i.a. bekannt ist, muss dem Konstruktor normalerweise nur die Port-Nr übergeben werden. Alternativ kann dem Konstruktor zusätzlich noch die maximale Grösse der Warteschlange für anstehende Verbin- dungswünsche übergeben werden (backlog). Ohne diese Angabe wird hierfür der Defaultwert 50 verwendet. Bei voller Warteschlange werden weitere Verbindungswünsche zurückgewiesen. Es existiert auch ein Konstruktor, dem zusätzlich eine IP-Adresse (als InetAddress-Objekt) übergeben werden kann. Dies ermöglicht für Server-Prozesse, die sich auf einem über mehrere IP-Adressen verfügenden Rechner befinden, die Festlegung einer bestimmten Horch-Adresse .
◇ Alternativ kann auch ein Socket erzeugt werden, der an keine lokale Adresse gebunden ist (parameterloser Konstruktor). In diesem Fall ist ein späteres Binden an eine lokale Adresse mit der Memberfunktion bind(...) möglich.
◇ Falls ein Security-Manager installiert ist, überprüft dieser sowohl in den Konstruktoren als auch in der Methode bind(..), ob an der lokalen Adresse ein anschliessendes Warten ("Horchen") auf Verbindungswünsche zulässig ist. Bei Unzulässigkeit wird eine SecurityException geworfen.
◇ Durch Aufruf der Methode accept() wird ein ServerSocket in den blockierenden Wartezustand versetzt, in dem er auf Verbindungswünsche durch Clients wartet ("Horch-Zustand"). Für einen akzeptierten Verbindungswunsch erzeugt accept() einen "Kommunikations-Socket". Dieser Socket ist an ein neues Port gebunden. Dies ermöglicht einem Multi-Thread-Server (Server, bei dem die Kommunikation mit einem Client jeweils in einem eigenen Thread stattfindet) sofort nach dem Akzeptieren eines Verbindungswunsches an dem "Horch"-Port auf weitere Verbindungswünsche zu warten. Falls ein Security-Manager installiert ist, überprüft dieser ob die Erzeugung des vorgesehenen "Kommunikations- Sockets" zulässig ist. Bei Unzulässigkeit wird eine SecurityException geworfen.
◇ Auch ein ServerSocket-Objekt sollte geschlossen werden, wenn es nicht mehr benötigt wird
◇ Viele Memberfunktionen (und Konstruktoren) der Klasse ServerSocket können Exceptions verschiedenen Typs werfen (s. API-Dokumentation)
◇ Konstruktoren der Klasse ServerSocket (Auswahl)
◇ Memberfunktionen der Klasse ServerSocket (Auswahl)
public ServerSocket() Erzeugung eines an keine lokale Adresse gebundenen Sockets throws IOException
public ServerSocket(int port) Erzeugung eines Server-Sockets, der an die IP-Adresse 0.0.0.0 throws IOException (wildcard) und die Port-Nr. port gebunden ist. Herstellung der Bereitschaft, auf Verbindungswünsche zu warten Für port==0 kann auf allen Ports gewartet werden. Die maximale Grösse der Warteschlange wird auf 50 gesetzt
public void bind(SocketAddress adr) Binden des Sockets an die lokale Socket-Adresse adr throws IOException (bei der Adresse muss es sich um eine INET-Adr. handeln)
public Socket accept() Warten auf Verbindungswünsche von Clients. Bei Akzep- throws IOException tieren Erzeugung eines "Kommunikations-Sockets"
public void close() throws IOException Schliessen des Sockets
Memberfunktionen zum Ermitteln der lokalen Adresse, sowohl als INET-Adresse (SocketAddress-Objekt) als auch getrennt für IP-Adresse und Port-Nr), s. API-Dokumentation
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 817 – 00 – TH – 01 -----------------------------------------------------------------------------------
Kommunikation über INET-Stream-Sockets in Java •••• Prinzipielles Realisierungsgerüst des Servers 1. Erzeugung eines ServerSocket-Objekts ServerSocket srvsk = new ServerSocket(port);
Binden des Sockets an ein Port 2. Warten auf Verbindungswünsche durch Socket comsk = null;
Clients mittels accept(), damit while ((comsk=srvsk.accept())!=null)
Erzeugung eines Socket-Objektes { (i.a. in einer Schleife) 3. Kommunikation mit dem Client über das Socket-Objekt
▻ Ermittlung der vom Socket-Objekt InputStream is = comsk.getInputStream();
bereitgestellten Stream-Objekte OutputStream os = comsk.getOutputStream();
▻ Erzeugung der für die Kommunikation // zum Beispiel :
tatsächlich einzusetzenden Stream-Objekte DataInputStream dis =new DataInputStream(is); (Objekte von Stream-Filter-Klassen) DataOutputStream dos=new DataOutputStream(os);
▻ Kommunikation mittels // zum Beispiel :
Lese- und Schreiboperationen str = dis.readUTF();
über die Stream-Objekte dos.writeUTF(str);
▻ nach Beendigung der Kommunikation dis.close();
Schliessen der Stream-Objekte; dos.close();
4. Schliessen des Socket-Objektes comsk.close(); }
•••• Prinzipielles Realisierungsgerüst des Clients 1. Erzeugung eines Socket-Objektes Socket sock = new Socket(name, port);
Festlegung des Servers (Name oder IP-Adresse) und des Ports � Verbindungswunsch an Server 2. Kommunikation mit dem Server über das Socket-Objekt
▻ Ermittlung der vom Socket-Objekt OutputStream os = sock.getOutputStream();
bereitgestellten Stream-Objekte InputStream is = sock.getInputStream();
▻ Erzeugung der für die Kommunikation // zum Beispiel :
tatsächlich einzusetzenden Stream-Objekte DataOutputStream dos=new DataOutputStream(os); (Objekte von Stream-Filter-Klassen) DataInputStream dis =new DataInputStream(is);
▻ Kommunikation mittels // zum Beispiel :
Schreib- und Leseoperationen dos.writeUTF(str);
über die Stream-Objekte str = dis.readUTF();
▻ nach Beendigung der Kommunikation dis.close();
Schliessen der Stream-Objekte; dos.close();
3. Schliessen des Socket-Objektes sock.close();
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 818 – 01 – TH – 02 ------------------------------------------------------------------------------------
Demonstrationsbeispiel zur Kommunikation über INET-Stream-Sockets in Java (1)
•••• Zu lösende Aufgabe : Filterung von Text
◇ Der zu filternde Text wird in einem Client-Programm zeilenweise von der Standard-Eingabe eingelesen und über eine INET-Stream-Socket-Verbindung zu einem Server-Programm gesendet. Der Name des Server-Rechners und die Port-Nr des Server-Programms können durch Kommandozeilen-Parameter festgelegt werden. Falls das nicht erfolgt : Verwendung von Defaults.
◇ Das Server-Programm filtert die erhaltenen Zeilen-Strings mittels eines Filter-Objektes und sendet anschliessend die gefilterten Strings über die INET-Stream-Socket-Verbindung zum Client zurück. Die Port-Nr des Server-Programms kann durch einen Kommandozeilen-Parameter festgelegt werden. Falls das nicht erfolgt, wird eine Default-Port-Nr verwendet.
◇ Das Client-Programm gibt die erhaltenen gefilterten Zeilen-Strings in die Standard-Ausgabe aus.
◇ Die Art der Filterung wird durch die Klasse des vom Server-Programm eingesetzten Filter-Objekts festgelegt. Diese muss das Interface TextFilter implementieren. Hier : Klasse UpcaseFilter (Umwandlung aller Buchstaben in Gross-Buchstaben)
•••• Quelldatei mit Definition eines Interfaces für Text-Filter (TextFilter.java)
•••• Beispiel einer Text-Filter-Klasse : Quelldatei UpcaseFilter.java
// TextFilter.java // Definition eines Interfaces fuer Klassen zur TextFilterung public interface TextFilter { public String filterString(String str); }
// UpcaseFilter.java // Klasse zur Filterung von Strings : Umwandlung aller Buchstaben in Gross-Buchstaben // Implementierung des Interfaces TextFilter public class UpcaseFilter implements TextFilter { public String filterString(String str) { return str.toUpperCase(); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 818 – 02 – TH – 02 ------------------------------------------------------------------------------------
Demonstrationsbeispiel zur Kommunikation über INET-Stream-Sockets in Java (2) •••• Quelldatei mit Klasse für Serverprogramm (FilterServer.java)
// FilterServer.java // Start-und Steuer-Klasse eines Servers zum Filtern von Strings import java.net.*; import java.io.*; public class FilterServer { static final int DEF_PORT = 60290; public static void main(String[] args) throws IOException { int port = DEF_PORT; if (args.length>0) port=Integer.parseInt(args[0]); PrintStream stdout = System.out; ServerSocket servsock = new ServerSocket(port); stdout.println("FilterServer"); stdout.println("Lokale Adresse : " + servsock.getInetAddress()); stdout.println("Lokales Port : " + servsock.getLocalPort() + '\n'); Socket comsock = null; TextFilter fil = new UpcaseFilter(); while ((comsock=servsock.accept())!=null) { stdout.print("Verbindung zu : "); stdout.print(comsock.getInetAddress()); stdout.println(" (Port : " + comsock.getPort() +")"); DataInputStream in = new DataInputStream(comsock.getInputStream()); DataOutputStream out = new DataOutputStream(comsock.getOutputStream()); String line = null; boolean goon = true; while (goon) { try { line = in.readUTF(); line = fil.filterString(line); out.writeUTF(line); } catch (EOFException ex) { stdout.println("Verbindung geschlossen"); goon = false; } catch (IOException ex) { stdout.println(ex.getMessage()); goon = false; } } in.close(); out.close(); comsock.close(); } servsock.close(); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 818 – 03 – TH – 02 ------------------------------------------------------------------------------------
Demonstrationsbeispiel zur Kommunikation über INET-Stream-Sockets in Java (3)
•••• Quelldatei mit Klasse für Clientprogramm (FilterClient.java)
// FilterClient.java // Filterung von Strings, die ueber die Standardeingabe eingegeben werden // Demonstrationsbeispiel zur Socket-Kommunikation import java.io.*; import java.net.*; public class FilterClient { static final String DEF_HOST = "localhost"; static final int DEF_PORT = 60290; public static void main(String[] args) throws IOException { String host = DEF_HOST; int port = DEF_PORT; switch(args.length) { case 2 : port = Integer.parseInt(args[1]); case 1 : host = args[0]; break; } PrintStream stdout = System.out; BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); Socket sock = new Socket(host, port); DataInputStream in = new DataInputStream(sock.getInputStream()); DataOutputStream out = new DataOutputStream(sock.getOutputStream()); String line; stdout.print("Eingabe ? "); while ((line=stdin.readLine())!=null) { out.writeUTF(line); line=in.readUTF(); stdout.println("Ausgabe : " + line); stdout.print("Eingabe ? "); } in.close(); out.close(); sock.close(); } }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 821 – 00 – TH – 01 -----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java - Allgemeines •••• Konzept von RMI
◇ Ein objektorientiertes System besteht aus einer Ansammlung von Objekten, die miteinander in Kommunikations- beziehungen stehen. Jede Kommunikationsbeziehung zwischen Objekten kann als Client-Server-Beziehung aufgefasst werden : Ein Server-Objekt stellt Dienstleistungen zur Verfügung, die von Client-Objekten durch den Aufruf von Methoden des Server-Objekts (= Senden von Botschaften an das Server-Objekt) genutzt werden können
◇ Remote Method Invocation (RMI) realisiert eine Übertragung des Konzepts des Prozedur-Fernaufrufs (Remote
Procedure Call, RPC) auf eine objektorientierte Umgebung.
◇ RMI erlaubt den Aufruf von Methoden für Objekte, die sich in anderen virtuellen Maschinen befinden, einschliesslich solcher virtueller Maschinen, die auf anderen Rechnern laufen. � Kommunikation zwischen Objekten über Rechnergrenzen hinweg � verteilte Objekte
◇ RMI ist die Java-spezifische Implementierung eines Systems für verteilte Objekte "Natürliche" Integration des verteilten Objekt-Modells in die Sprache Java unter Ausnutzung ihrer Konzepte und Beibehaltung ihrer Objekt-Semantik � Ein entfernter Methodenaufruf sieht wie ein normaler lokaler Methodenaufruf aus (transparenter entfernter Methodenaufruf)
◇ Bestandteil des Java-API (ab JDK 1.1, modifiziert und erweitert in JDK 1.2) •••• Weitere wesentliche Eigenschaften von RMI
◇ Anwendungen stehen zwei Mechanismen zur Erlangung von Referenzen auf entfernte Objekte zur Verfügung :
▻ Nachfragen bei einem RMI-eigenen Namensdienst (rmiregistry)
▻ Übergabe als Parameter und/oder Rückgabewerte von entfernten Funktionsaufrufen
◇ Die eigentliche Kommunikation zwischen verteilten Objekten wird vom RMI-Laufzeitsystem unter Einsatz von Sockets durchgeführt. Einzelheiten bleiben der eigentlichen Anwendung (und ihrem Programmierer) aber verborgen.
◇ RMI ermöglicht die Übergabe von Objekten als Parameter und Rückgabewerte Das RMI-Laufzeitsystem stellt die notwendigen Mechanismen zur Übertragung von Objekt-Daten und -Code zur Verfügung (� Kopieren von Objekten) Diese beruhen auf
▻ dem Java-Konzept der Objekt-Serialisierung (object serialization)
▻ sowie der Java-Eigenschaft des dynamischen Ladens von Code (dynamic code downloading) � Erzeugung von Objekten, deren Klassen-Implementierung (Java-Byte-Code) lokal nicht verfügbar ist
◇ Das dynamische Laden von Code ermöglicht die dynamische Änderung des Verhaltens von Server und/oder Client
◇ Unterstützung von Callbacks vom Server zum Client Übergabe von Referenzen auf – im Client vorhandene – entfernte Objekte als Parameter im entfernten Methodenaufruf.
◇ Verteilte Garbage Collection Einbeziehung von entfernten Objekten in den Garbage Collection Mechanismus von Java RMI stellt sicher, daß dann und nur dann entfernte Objekte (remote objects) vernichtet werden, wenn weder eine lokale noch eine entfernte Referenz auf das jeweilige Objekt existiert.
◇ Einbettung in die Sicherheitsmechanismen der Java-Plattform Verwendung von Security-Manager, Class Loader und Policy Files zur Überprüfung der Zulässigkeit des Ladens von entferntem Code und des Ausführens von Code (Resourcenzugriff)
◇ Flexibilität und Erweiterbarkeit, z.B.
▻ Implementierung unterschiedlicher Referenz-Semantiken für entfernte (Server-) Objekte (z.Zt im Standard-API implementiert : UnicastRemoteObject und Activatable )
▻ Einsatz unterschiedlicher Socket-Typen in der Transportschicht von RMI (Ersatz des standardmäßig verwendeten Socket-Typs (TCP-Protokoll) durch SSL-Sockets oder selbstdefinierte Socket-Typen)
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 822 – 01 – TH – 02 -----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java – Funktionsweise (1) •••• RMI –Architektur
◇ Das RMI-System besteht aus drei Schichten :
▻ Stub-/Skeleton-Schicht
▻ RMI-Referenz-Schicht
▻ RMI-Transport-Schicht
◇ Die Stub-/Skeleton-Schicht bildet die Schnittstelle zwischen den Bestandteilen der verteilten Applikation (Client-Objekt und Server-Objekt) und dem restlichen RMI-System (RMI-Laufzeitsystem). Der Stub ist ein Stellvertreter-Objekt (Proxy) des Server-Objekts auf der Clientseite, der die gleiche Methoden- Aufruf-Schnittstelle wie das Server-Objekt anbietet. Er nimmt die RMI-Aufrufe des Clients entgegen, wandelt die Methoden-Aufruf-Parameter mittels Objekt-Serialisie- rung in serielle Byte-Streams um (marshalling) und leitet diese zusammen mit den für den Aufruf der Serverfunktion benötigten Informationen (Identifikation des Ziel-Objekts und der aufzurufenden Methode) an die RMI-Referenzschicht weiter Umgekehrt erhält er von der RMI-Referenzschicht die Rückgabewerte eines RMI-Aufrufs als Byte-Streams, deseriali- siert diese (ummarshalling) und reicht sie an das aufrufende Client-Objekt weiter. Das Skeleton nimmt auf der Serverseite die RMI-Aufrufe von der RMI-Referenzschicht entgegen, deserialisiert die als Byte-Streams erhaltenen Parameter und ruft mit diesen die eigentlich auszuführende im Server-Objekt implemen- tierte Methode auf. Nach Bendigung dieser Funktion nimmt es deren Rückgabewerte entgegen und leitet sie nach Serialisierung an die RMI-Referenzschicht weiter. In früheren Java-Versionen wurde hierfür ein eigenes Skeleton-Objekt eingesetzt. In neueren Versionen wird die Funktionalität des Skeletons durch einen allgemeinen Verteiler des RMI-Laufzeit- systems ersetzt. Es muss daher kein eigenes Skeleton-Objekt mehr erzeugt werden. Der Stub muss dagegen an das jeweilige Server-Objekt angepaßt sein. Seine Klasse wird aus der Server-Objekt-Klasse mittels eines RMI-Compilers (rmic) generiert. (Der RMI-Compiler war früher auch zuständig für die Erzeugung der Skeleton-Klasse) Ab dem JDK 5.0 kann das Stub-Objekt dynamisch zur Laufzeit erzeugt werden. � Aufruf von rmic nicht erforderlich wenn auch der Client-Code mit dem JDK 5.0 erzeugt wurde.
◇ Die RMI-Referenz-Schicht ist für die Lokalisierung des jeweiligen Kommunikationspartners (Server bzw Client) zuständig. Sie beinhaltet den RMI-Namensdienst (Registry) und verwaltet die Referenzen auf entfernte Objekte. Unter Berücksichtigung der jeweiligen Referenz-Semantik gibt sie die vom Stub erhaltenen RMI-Aufrufe einschließ- lich deren Parameter (Byte-Streams) an die RMI-Transportschicht weiter. Auf der Serverseite nimmt sie die RMI-Aufrufe und deren Parameter von der RMI-Transportschicht entgegen, aktiviert gegebenenfalls das Server-Objekt und leitet die Aufrufe an das Skeleton weiter. Analog ist sie an der Übermittlung der Rückgabewerte beteiligt.
◇ In der RMI-Transport-Schicht werden die Kommunikationsverbindungen verwaltet und die eigentliche Kommu- nikation zwischen verschiedenen Adressräumen (JVMs) abgewickelt. Üblicherweise werden hierfür Sockets eingesetzt.
Skeleton
Server-Objekt
RMI-Referenz-Schicht
RMI-Tranport-Schicht
RMI-Referenz-Schicht
RMI-Tranport-Schicht
Client-Objekt
Stub
RMI- Laufzeit- System
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 822 – 02 – TH – 01 -----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java – Funktionsweise (2) •••• Übertragung von Parametern und Rückgabewerten
◇ Die Parameter und Rückgabewerte von RMI-Aufrufen werden mittels Objekt-Serialisierung als Byte-Streams übertragen. �Übertragbare Objekte müssen serialisierbar sein, d.h. das Interface java.io.Serializable implementieren.
◇ einfache Datentypen : Übertragung der Werte (Call by Value)
◇ lokale Objekte (non-remote objects) : Übertragung einer Kopie des Objekts (Call by Copy) Für Rückgabewerte wird beim Aufrufer ein neues Objekt erzeugt
◇ entfernte Objekte (remote objects) : Übertragung einer Referenz auf das Objekt (Call by Reference) Die Referenz ist das zum Objekt gehörende Stub-Objekt. (das seinerseits per Kopie übertragen wird)
◇ In dem im Byte-Stream für ein übertragenes Objekt enthaltenen Klassen-Deskriptor ist auch die URL über die der Klassen-Code (Java Byte Code) zugänglich ist, vermerkt. Dies ermöglicht es dem empfangenden System, den Klassen-Code dynamisch zu laden, falls er nicht lokal verfügbar ist. (Dynamic Code Downloading). Eine derartige Situation kann auftreten, wenn das übertragene Objekt eine Instanz eines Untertyps des deklarierten Parametertyps ist. Ein Untertyp in diesem Sinn ist entweder eine Klasse, die ein Interface, das als Parametertyp dekla- riert ist, implementiert oder eine von der Parameterklasse abgeleitete Klasse. •••• RMI-Registry
◇ Die RMI-Registry ist ein einfacher Namensdienst, der es Clients ermöglicht, entfernte Objekte über ihren Namen zu lokalisieren.
◇ Eine RMI-Registry muß lokal auf dem System, das Objekte für RMI-Aufrufe (entfernte Objekte) bereitstellt (RMI- Server) existieren.
◇ Üblicherweise wird die RMI-Registry in einer eigenen JVM als Hintergrundprozeß gestartet. Defaultmäßig "horcht" sie auf Port 1099. Sie kann aber auch mit einer anderen Port-Nummer gestartet werden. Kommando : [start] rmiregistry [port] (Windows) rmiregistry [port] & (Linux)
◇ Ein entferntes Objekt, das über die Registry zugänglich sein soll, muß vom Server-Prozeß der Registry bekannt gemacht (registriert, "gebunden") werden.
◇ Ein Client, der einen RMI-Aufruf ausführen möchte, benötigt eine Referenz auf das entsprechende (entfernte) Server- Objekt. Diese erhält er durch eine Nachfrage ("lookup") bei der RMI-Registry des Server-Rechners. Falls für das – über einen Namen referierte – Objekt ein Eintrag vorhanden ist, liefert die Registry sein als Referenz dienendes Stub-Objekt zurück.
◇ Typischerweise wird die RMI-Registry nur zur Lokalisierung des ersten vom Client referierten entfernten Objekts verwendet. Weitere gegebenenfalls benötigte entfernte Objekte können dann über dieses Objekt ermittelt werden (als Parameter bzw Rückgabewerte von RMI-Aufrufen)
◇ Die Kommunikation mit der RMI-Registry erfolgt üblicherweise über das von der Java-Klasse java.rmi.Naming bereitgestellte Interface (statische Methoden)
◇ Tatsächlich stellt die RMI-Registry bereits selbst ein besonderes entferntes Objekt dar, zu dem auch mittels RMI, das durch die Naming-Funktionen gekapselt wird, zugegriffen wird.
Server-Objekt
Client-Objekt
RMI-Registry 2 : Nachfrage
1:Registrierung
3 : RMI-Aufruf
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 822 – 03 – TH – 02 -----------------------------------------------------------------------------------
Remote Method Invocation (RMI) von Java – Funktionsweise (3) •••• Dynamisches Laden von Code (Dynamic Code Downloading)
◇ Eine hervorstechende Eigenschaft von Java ist die Fähigkeit, dynamisch Code von jeder URL in eine laufende Java Virtual Machine (JVM) zu laden. I.a. wird die URL auf ein anderes physikalisches System verweisen. � Eine JVM kann Code ausführen, der nie auf ihrem eigenen System installiert worden ist.
◇ Diese Fähigkeit wird auch vom RMI-System genutzt :
▻ Zum Laden des Codes für den Stub des Server-Objekts durch den Client (ab dem JDK 5.0 nicht mehr erforderlich). � Die Stub-Klasse muß nicht lokal zur Verfügung stehen (ab dem JDK 5.0 wird sie lokal beim Client aus dem RMI-Interface erzeugt)
▻ Zum Laden des Codes für als Parameter in oder Rückgabewerte von RMI-Aufrufen übergebene Objekte (sowohl lokale Objekte als auch entfernte Objekte)
◇ Das dynamische Laden von Code erfordert das Setzen der Property java.rmi.server.codebase in der JVM des das Objekt bzw die Klasse zur Verfügung stellenden Prozesses : - bei Stubs von Server-Objekten : in der JVM des RMI-Server-Prozesses, der ein entferntes Objekt registriert (ab dem JDK 5.0 nicht mehr notwendig) - bei als Parameter übergebenen Objekten : in der JVM des RMI-Client-Prozesses - bei Objekten, die von RMI-Aufrufen zurückgegeben werden : in der JVM des Server-Prozesses Als Wert der codebase-Property ist die URL, von der der Klassen-Code geladen werden kann, anzugeben. Diese URL kann sich auf ein drittes System beziehen.
◇ Wenn der Server-Prozeß ein entferntes Objekt unter einem Namen bei der RMI-Registry registriert, wird der in der Server-JVM gesetzte codebase-Wert (URL !) zusammen mit der Objekt-Referenz (Stub-Objekt) gespeichert. Voraussetzung : Der Code der Stub-Klasse darf nicht über die CLASSPATH-Environment-Variable der JVM der RMI-Registry erreichbar sein. (gilt nicht ab dem JDK 5.0, da muss die .class-Datei des RMI-Interfaces über die CLASSPATH-Environment-Variable der JVM der RMI-Registry erreichbar sein)
◇ Der Client-Prozeß erhält auf seine Nachfrage bei der RMI-Registry das Stub-Objekt als Referenz auf das Server- Objekt. Falls er den Stub-Klassen-Code nicht über seine CLASSPATH-Environment-Variable lokal findet, versucht er bis einschliesslich dem JDK 1.4 den Code von der mit dem Stub-Objekt verbundenen URL (codebase-Wert) zu laden. (ab dem JDK 5.0 wird der Code lokal aus dem RMI-Interface erzeugt) Voraussetzung : Der RMI-Client-Prozeß hat einen Security-Manager installiert, der das Laden des Stubs erlaubt (z.B. RMISecurityManager). In Java 2 (ab JDK 1.2) erfordert dies zusätzlich ein entsprechend konfiguriertes Security Policy File (Default : Datei .java.policy im Heimat-Verzeichnis des Users) Anmerkung : Der Security-Manager wird bereits für den Zugriff zur Registry benötigt.
◇ Analog erfolgt das Laden von Klassen-Codes für Objekte, die dem Server-Objekt vom Client-Objekt als Parameter in RMI-Aufrufen übergeben werden (einschliesslich das Laden aller weiteren von diesen benötigten Objekte). Das gilt auch für das JDK 5.0 ! Voraussetzungen : Der codebase-Wert im Client-Prozeß ist auf die richtige URL gesetzt und das Server-Objekt kann den Code nicht lokal über seine CLASSPATH-Environment-Variable finden. Außerdem muß im Server ein Security-Manager installiert sein.
Client-Objekt
myHost codebase-URL
(http)
RMI-Registry Server-Objekt
Server-Prozeß, der entferntes Objekt
erzeugt
java.rmi.server.codebase
=http://myHost/mydir/
1. Registrierung des entfernten Server-Objekts
2. Namens- Nachfrage
3. Rückgabe eines Stub-Objekts
4. Erfragen des Klassen-Codes für Stub-Objekt
5. Rückgabe des Klassen- Codes des Stub-Objekts
6. RMI-Aufruf
4. u. 5 nicht bei JDK 5.0
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 823 – 01 – TH – 02 ------------------------------------------------------------------------------------
Java-RMI - Interfaces und Klassen (1)
•••• RMI-Packages Das RMI-API von Java wird durch die folgenden Packages zur Verfügung gestellt :
▻ java.rmi grundlegendes Package
▻ java.rmi.activation Unterstützung für die RMI Object Activation
▻ java.rmi.dgc Klassen und Interfaces für die RMI Distributed Garbage Collection
▻ java.rmi.registry Klassen und Interfaces für die RMI-Registry
▻ java.rmi.server Klassen und Interfaces zur Unterstützung der Server-Seite von RMI
•••• Überblick über die wichtigsten Interfaces und Klassen des RMI-API Für Anwenderprogramme sind vor allem die folgenden Interfaces und Klassen von Bedeutung :
interface
Remote (java.rmi)
abstract class
RemoteObject (java.rmi.server)
abstract class
RemoteServer (java.rmi.server)
class
Activatable (java.rmi.activation)
class
UnicastRemoteObject (java.rmi.server)
class
RemoteException (java.rmi)
class
Naming (java.rmi)
class
RMISecurityManager (java.rmi)
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 823 – 02 – TH – 03 ------------------------------------------------------------------------------------
Java-RMI - Interfaces und Klassen (2)
•••• Die wichtigsten Interfaces und Klassen des Java-RMI-API - Kurzbeschreibung
◇ interface Remote (Package : java.rmi) "Basis"-Interface für alle Interfaces, deren Methoden mittels RMI aufrufbar sein sollen. Alle Klassen, deren Objekte mittels RMI ansprechbar sein sollen, müssen direkt oder indirekt – über abgeleitete Interfaces – dieses Interface implementieren. Mittels RMI können nur die Methoden, die in einem von Remote abgeleiteten Interface (� remote interface) spezi- fiziert sind, aufgerufen werden.
◇ class RemoteObject (Package : java.rmi.Server) Abstrakte Klasse, die einige Methoden der Klasse java.lang.Object für entfernt nutzbare Objekte (remote
objects) überschreibt und damit die entsprechenden Fähigkeiten für derartige Objekte implementiert. (spezielle Implementierungen der Methoden hashCode(), equals() und toString())
◇ class RemoteServer (Package : java.rmi.Server) Abstrakte Superklasse der Klassen für entfernt nutzbare Server-Objekte. Sie stellt ein gemeinsames Framework zur Unterstützung unterschiedlichster Semantiken für entfernte Referenzen zur Verfügung, die durch die von ihr abgeleiteten Klassen implementiert werden Die zur Erzeugung und Exportierung von Objekten an das RMI-Laufzeitsystem benötigten Methoden (Konstruktoren und gegebenenfalls weitere Methoden) werden durch die von dieser Klasse abgeleiteten Klassen bereitgestellt. U.a. stellt diese Klasse auch eine statische Methode zum Ermitteln des aufrufenden Client-Rechners zur Verfügung.
◇ class UnicastRemoteObject (Package : java.rmi.Server) Von der Klasse RemoteServer abgeleitete Klasse für einfache – nicht replizierbare – entfernte Objekte, deren Referenzen nur gültig sind, solange die Objekte aktiv sind. Sie stellt die Unterstützung für Punkt-zu-Punkt-Verbindungen zu aktiven Objekten (bezüglich Aufrufe, Parameter, Rückgabewerte) unter Verwendung von TCP-Sockets bereit Durch Übergabe eines int-Parameters an den Konstruktor kann die Port-Nummer festgelegt werden. Wird kein Parameter übergeben, wird vom System ein anonymes Port gewählt. Eigene Klassen, die diese Referenz-Semantik bereitstellen sollen, müssen – unter Implementierung eines geeigneten remote interfaces - von dieser Klasse abgeleitet werden.
◇ class Activatable (Package : java.rmi.Activation) Von der Klasse RemoteServer abgeleitete Klasse für entfernte Objekte, deren Referenzen auch gültig sind, wenn die Objekte inaktiv und persistent ausgelagert sind Diese Objekte können bei Bedarf wieder aktiviert werden. Eigene Klassen, die diese Referenz-Semantik bereitstellen sollen, müssen – unter Implementierung eines geeigneten remote interfaces - von dieser Klasse abgeleitet werden.
◇ class RemoteException (Package : java.rmi) Superklasse der kommunikationsorientierten Exceptions, die bei RMI auftreten können. Alle Methoden eines remote interfaces müssen diese Exception weiterreichen können, d.h. in ihrem Funktionskopf muß eine entsprechende Exception-Spezifikation (throws-Klausel) enthalten sein.
◇ class Naming (Package : java.rmi) Nicht ableitbare Klasse (final), die statische Methoden zum Zugriff zur RMI-Registry bereitstellt
◇ class RMISecurityManager (Package : java.rmi) Beispiel eines von RMI-Anwendungen für das dynamische Laden von Code benötigten Security-Managers. Der RMI Class Loader kann ohne installierten Security-Manager keinen Code von URLs, die auf einen entfernten Rechner verweisen, laden.
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 824 – 01 – TH – 02 -----------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (1)
•••• Auszuführende Schritte
▶ Definition eines Interfaces für die RMI-Aufrufe (remote interface)
▶ Erstellung eines Servers (Implementierung des Interfaces und der Server-Start-Funktionalität)
▶ Entwicklung eines Clients, der unter Nutzung dieses Interfaces RMI-Aufrufe ausführt
▶ Erzeugung der Stub-Klasse (ab dem JDK 5.0 nicht mehr erforderlich)
▶ Starten der RMI-Registry auf dem Server-Rechner
▶ Start des Servers und des Clients
•••• Definition eines Interfaces für die RMI-Aufrufe (remote interface)
◇ Alle Methoden des Server-Objekts, die über RMI aufrufbar sein sollen, sind in einem Interface zu deklarieren (RMI-Methoden)
◇ Eigenschaften dieses RMI-Interfaces :
► Das Interface muß public deklariert werden
► Das Interface muß von dem Interface java.rmi.Remote abgeleitet sein (� remote interface).
► Jede Methode des Interfaces muß die Exception java.rmi.RemoteException als werfbar deklarieren (Exception-Deklaration : throws java.rmi.RemoteException)
◇ Die Klasse der RMI-Server-Objekte muß dieses Interface implementieren (RMI-Server-Klasse). Nur die Methoden der Server-Objekte, die in diesem Interface enthalten sind, sind auch entfernt aufrufbar. Alle weiteren eventuell vorhandenen Methoden sind nur lokal ansprechbar.
◇ Der Client muß das Stub-Objekt, das er als lokale Referenz auf das entfernte Server-Objekt erhält, immer als eine Instanz dieses Interfaces referieren . Der hierfür notwendige Type-Cast ist zulässig, da auch die Stub-Klasse dieses Interface implementiert.
◇ Übersetzung der Java-Quell-Datei (z.B. MyServer.java) � Erzeugung einer Java-Bytecode-Datei (MyServer.class)
•••• Klassendiagramm für einen einfachen RMI-Server
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 824 – 02 – TH – 01 -----------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (2) •••• Erstellung eines Servers
◇ Zur Realisierung eines RMI-Servers werden benötigt :
► Eine das RMI-Interface implementierende Klasse (RMI-Server-Klasse)
► Die Server-Start-Funktionalität. Häufig wird die Server-Start-Funktionalität durch die main()-Methode der RMI-Server-Klasse realisiert. Diese main()-Methode kann aber auch in einer anderen – speziell hierfür vorgesehenen - Klasse enthalten sein.
◇ Die RMI-Server-Klasse muß
► wenigstens ein RMI-Interface (remote interface) implementieren
► von einer Unterklasse der Klasse java.rmi.server.RemoteServer abgeleitet sein
► einen Konstruktor definieren, der die Exception java.rmi.RemoteException werfen kann
► alle im implementierenden RMI-Interface enthaltenen Methoden definieren
◇ Die Server-Start-Funktionalität beinhaltet :
▻ Erzeugung und Installation eines Security Managers
▻ Erzeugung eines oder mehrerer RMI-Server-Objekte (Instanzen der RMI-Server-Klasse)
▻ Registrierung wenigstens eines dieser Objekte bei der RMI-Registry
◇ Erzeugung und Installation eines Security-Managers In jeder JVM, in der Code von anderen Quellen als den durch die CLASSPATH-Environmentvariable festgelegten geladen werden soll, muß ein Security-Manager installiert sein. Falls noch kein Security-Manager installiert ist, muß der Server einen installieren – entweder eine Instanz der Klasse RMISecurityManager oder einer selbstdefinierten Security-Manager Klasse if (System.getSecurityManager()==null) { System.setSecurityManager(new RMISecurityManager()); }
◇ Registrierung eines RMI-Server-Objektes bei der lokalen RMI-Registry Mittels der statischen Methode rebind() der Klasse Naming : Parameter : name - URL-formatierter String, der das zu registrierende Objekt bezeichnet - Allgemeine Form : "//host:port-nr/ObjectName". - Wenn die RMI-Registry auf dem Default-Port 1099 läuft, können die Angabe des Hosts (host) und der Port-Nr. (port-nr) weggelassen werden, es reicht die Angabe von "ObjectName". - "ObjectName" ist ein beliebiger Name unter dem das Objekt registriert werden soll. obj Name des Objekts unter dem es angelegt worden ist und im Programm referiert wird. Beispiel : Naming.rebind("MyServer", serv); Die von der Methode werfbaren Exceptions müsssen gefangen werden.
◇ Jeder Aufruf einer RMI-Methode erfolgt in einem eigenen Thread. � Ein mittels RMI realisierter Server ist grundsätzlich ein Multithread-Server.
◇ Innerhalb einer RMI-Methode kann der Rechner des aufrufenden Clients mittels der von RemoteServer geerbten statischen Methode getClientHost() ermittelt werden : Funktionswert : String-Repräsentation des Client-Rechners
public static void rebind(String name, Remote obj) throws RemoteException, MalformedURLException
public static String getClientHost() throws ServerNotActiveException
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 824 – 03 – TH – 03 ------------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (3)
•••• Entwicklung eines Clients
◇ Wesentliche Funktionalität des Clients :
► Erzeugung und Installation eines Security-Managers
►►►► Erfragen einer Referenz auf das entfernte RMI-Server-Objekt bei der RMI-Registry
► Aufruf der RMI-Methoden über die erhaltene Referenz
◇ Die Erzeugung und Installation eines Security Managers erfolgt analog wie beim Server : if (System.getSecurityManager()==null) { System.setSecurityManager(new RMISecurityManager()); }
◇ Erfragen einer Referenz auf das entfernte RMI-Server-Objekt bei der RMI-Registry Mittels der statischen Methode lookup() der Klasse Naming : Parameter : name - URL-formatierter String, der das zu suchende Objekt bezeichnet - Allgemeine Form : "//host:port-nr/ObjectName". - Als Host (host) ist der Rechner (Name oder IP-Adresse) anzugeben, auf dem sich das gesuchte Objekt und die RMI-Registry befindet. - Wenn die RMI-Registry auf dem Default-Port 1099 läuft, kann die Angabe der Port-Nr. (port-nr) weggelassen werden - "ObjectName" ist der Name des Objekts, unter dem es in der Registry registriert worden ist. Die Methode Naming.lookup() erzeugt unter Verwendung von Host und Port-Nr. ein Registry-Stub-Objekt, über das die Methode lookup() für die Registry mit "ObjectName" als Parameter aufgerufen wird. Diese gibt – sofern ein Eintrag in der Registry vorhanden ist – ein Stub-Objekt für das gesuchte RMI-Server-Objekt zurück. Naming.lookup() gibt dieses Stub-Objekt als Referenz auf das RMI-Server-Objekt an den aufrufenden Client zurück (als Instanz des Interfaces Remote). Der Stub-Code wird – sofern er nicht lokal über die CLASSPATH-Environmentvariable gefunden wird – bis zum JDK 1.4 von der in der Registry für die Stub-Klasse abgelegten (und im Stub-Objekt angegebenen) Codebase geladen. Ab dem JDK 5.0 wird er lokal beim Client aus dem RMI-Interface erzeugt. Der Client wandelt den Typ des Stub-Objekts in den Typ des vom RMI-Server-Objekt implementierten RMI-Inter- faces um.
◇ Der Client referiert das erhaltene Stub-Objekt als Instanz des vom RMI-Server-Objekt implementierten RMI-Inter- faces. Über diese Instanz erfolgt ein Aufruf der RMI-Methoden.
public static Remote lookup(String name) throws NotBoundException, MalformedURLException, RemoteException
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 824 – 04 – TH – 03 ------------------------------------------------------------------------------------
Erzeugung einer RMI-Anwendung (4) •••• Erzeugung der Stub- (und früher auch Skeleton-)Klassen
◇ Ab dem (und für das) JDK 5.0 wird das Stub-Objekt dynamisch zur Laufzeit erzeugt � keine explizite Erzeugung der Stub-Klasse erforderlich (kein Aufruf von rmic).
◇ Für Vor-JDK-5.0-Anwendungen muss die Stub-Klasse (und gegebenenfalls auch die Skeleton-Klasse) explizit mittels des RMI-Compilers (Stub-Generators) rmic aus der das RMI-Interface implementierenden RMI-Server-Klasse und dem RMI-Interface erzeugt werden.
◇ Dem RMI-Compiler ist der voll-qualifizierte Package-Name der als Java-Byte-Code vorliegenden RMI-Server- Klasse als Parameter zu übergeben.
◇ Die den Java-Byte-Code der RMI-Server-Klasse enthaltende Datei (.class-file) sowie die Datei mit dem Java-Byte- Code (oder mit dem Quell-Code) des RMI-Interfaces müssen über die CLASSPATH-Environment-Variable erreich- bar sein.
◇ Zusätzlich kann beim Aufruf von rmic mit der "-d" Option angegeben werden, in welchem Ausgangs-Direc- tory die erzeugten Java-Byte-Code-Dateien (.class-files) für Stub (und gegebenenfalls Skeleton) abgelegt werden sollen (Ausgehend von diesem Directory erfolgt die Ablage in einer dem vollqualifizierten Package-Namen entspre- chenden Directory-Struktur). Ohne diese Angabe dient das aktuelle Directory als Ausgangs-Directory.
◇ Die von rmic erzeugten Klassen-Dateien für Stub (und gegebenefalls Skeleton) tragen den um _Stub bzw _Skel ergänzten Hauptnamen der RMI-Server-Klassen-Datei
◇ Beispiel : (ohne Verwendung eines Package-Namens) rmic –d G:\MyJava\classes\ MyServerImpl Hierdurch werden die Dateien MyServerImpl_Stub.class und MyServerImpl_Skel.class im Directory G:\MyJava\classes erzeugt. •••• Starten der RMI-Registry
◇ Üblicherweise wird die RMI-Registry als eigener Prozeß (in einer eigenen JVM laufend) auf dem Server-Rechner von der Kommandozeile aus mit dem Kommando rmiregistry gestartet. Falls die Registry nicht auf dem Default- Port 1099 arbeiten soll, muß die Port-Nr. beim Aufruf als Parameter angegeben werden. Beispiel : rmiregistry (� Registry läuft auf Port-Nr. 1099) rmiregistry 1248 (� Registry läuft auf Port-Nr. 1248)
◇ Alternativ kann die Registry auch lokal für den Server-Prozeß von diesem erzeugt und gestartet werden (Statische Methode createRegistry() der Klasse LocateRegistry)
◇ Achtung : Bis zum JDK 1.4 gilt : Die .class-Datei der Stub-Klasse(n) darf für die JVM der RMI-Registry nicht über die CLASSPATH-Environment-Variable erreichbar sein. Beim Start des Servers muss die Codebase, in der sich die Stub-Klasse befindet, angegeben werden. Alternative ab dem JDK 5.0 : Der RMI-Registry kann statt der Stubklasse auch die .class-Datei des RMI-Inter- faces zur Verfügung gestellt werden – entweder über die Codebase oder durch Bereitstellung einer direkten Zugriffs- möglichket ( .class-Datei des RMI-Interfaces befindet sich im Startverzeichnis der Registry oder die CLASSPATH- Variable enthält das Directory der .class-Datei ) •••• Start des Servers und des Clients
◇ Auf dem Server- und dem Client-Rechner sind jeweils eine JVM mit der jeweiligen Start-Klasse zu starten.
◇ Als Optionen können die Codebase (URL) und die zu verwendende Policy-Datei (Dateipfad) angegeben werden (Default für die Policy-Datei : .java.policy im Heimat-Verzeichnis des Users)
◇ Beispiel (für Server, kein Package-Name) : java –Djava.rmi.server.codebase=http://cd2/~thomas/classes/ -Djava.security.policy=my.policy MyServerImpl
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 825 – 01 – TH – 01 -----------------------------------------------------------------------------------
Einfaches Demonstrationsbeispiel zu RMI in Java (1) •••• Zu lösende Aufgabe : Filterung von Text
◇ Lösung der Aufgabe des Demonstrationsbeispiels zur INET-Socket-Kommunikation mittels RMI
◇ Definition eines Remote-Interfaces, das die Methode filterString() deklariert (RMI-Methode).
◇ Das Remote-Interface wird durch eine RMI-Klasse implementiert. In einem Server-Programm wird ein Objekt dieser Klasse instanziiert (� Remote-Objekt)
◇ Die RMI-Klasse implementiert in ihrer main()-Methode auch die Server Start-Funktionalität.
◇ Der zu filternde Text wird in einem Client-Programm zeilenweise von der Standard-Eingabe eingelesen Zur Filterung ruft der Client die RMI-Methode filterString() des Remote-Objekts im Server auf. Der Name des Server-Rechners kann beim Client-Start durch Kommandozeilen-Parameter festgelegt werden. Falls das nicht erfolgt : Verwendung von Defaults.
◇ Die RMI-Methode des Remote-Objekts des Servers filtert die erhaltenen Zeilen-Strings mittels eines Filter-Objektes und gibt die gefilterten Strings als Funktionswert der RMI-Methode an den Client zurück. Das Filter-Objekt wird dem Remote-Objekt bei der Erzeugung im Konstruktor zu übergeben.
◇ Das Client-Programm gibt die erhaltenen gefilterten Zeilen-Strings in die Standard-Ausgabe aus.
◇ Die Art der Filterung wird durch die Klasse des vom Server-Programm eingesetzten Filter-Objekts festgelegt. Diese muss das Interface TextFilter implementieren. (s. Beispiel zur INET-Socket-Kommunikation) Hier : Klasse UpcaseFilter (Umwandlung aller Buchstaben in Gross-Buchstaben)
◇ Die RMI-Registry wird auf dem Default-Port 1099 gestartet. Das Remote-Objekt wird unter dem Namen "TextFilter" in der RMI-Registry registriert •••• Quelldatei mit der Definition des Remote-Interfaces (RMITextFilter.java)
•••• Quelldatei mit Definition eines Interfaces für Text-Filter (TextFilter.java) (gleiches Interfaces wie im Beispiel zur INET-Socket-Kommunikation)
// RMITextFilter.java // Definition eines Remote-Interfaces fuer Klassen zur TextFilterung import java.rmi.*; public interface RMITextFilter extends Remote { public String filterString(String str) throws RemoteException; }
// TextFilter.java // Definition eines Interfaces fuer Klassen zur TextFilterung public interface TextFilter { public String filterString(String str); }
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 825 – 02 – TH – 01 -----------------------------------------------------------------------------------
Einfaches Demonstrationsbeispiel zu RMI in Java (2) •••• Quelldatei mit der Definition der RMI-Server-Klasse (RMIFilterServer.java)
•••• Beispiel einer Text-Filter-Klasse : Quelldatei UpcaseFilter.java (gleiche Klasse wie im Beispiel zur INET-Socket-Kommunikation)
// RMIFilterServer.java // Start-Klasse eines Servers zum Filtern von Strings // Implementierung des Remote-Interfaces RMITextFilter // Einfaches Demo-Beispiel zu RMI import java.rmi.*; import java.rmi.server.*; public class RMIFilterServer extends UnicastRemoteObject implements RMITextFilter { TextFilter fil; public RMIFilterServer(TextFilter tf) throws RemoteException { super(); fil = tf; } public String filterString(String str) throws RemoteException { try { System.out.println("Remote-Aufruf von : " + RemoteServer.getClientHost()); } catch (ServerNotActiveException ex) { System.err.println("kein Remote-Aufruf"); } return fil.filterString(str); } public static void main(String[] args) { if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); try { RMITextFilter fil = new RMIFilterServer(new UpcaseFilter()); Naming.rebind("TextFilter", fil); System.out.println("TextFilter bound in Registry"); } catch (Exception ex) { System.out.println("RMIFilterServer error : " + ex.getMessage()); ex.printStackTrace(); } } }
// UpcaseFilter.java // Klasse zur Filterung von Strings : Umwandlung aller Buchstaben in Gross-Buchstaben // Implementierung des Interfaces TextFilter public class UpcaseFilter implements TextFilter { public String filterString(String str) { return str.toUpperCase(); } }
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK FG TECHNISCHE INFORMATIK V – JV – 825 – 03 – TH – 02 -----------------------------------------------------------------------------------
Einfaches Demonstrationsbeispiel zu RMI in Java (3) •••• Quelldatei mit der Definition der RMI-Client-Klasse (RMIFilterClient.java)
// RMIFilterClient.java // Filterung von Strings, die ueber die Standardeingabe eingegeben werden // Einfaches Demo-Beispiel zu RMI import java.rmi.*; import java.io.*; public class RMIFilterClient { static final String DEF_HOST = "localhost"; public static void main(String[] args) { String host = DEF_HOST; if (args.length>0) host = args[0]; String server = "//"+host+"/"+"TextFilter"; if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); try { RMITextFilter fil = (RMITextFilter) Naming.lookup(server); PrintStream stdout = System.out; BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String line; stdout.print("Eingabe ? "); while ((line = stdin.readLine()) != null) { line = fil.filterString(line); // RMI-Aufruf !!! stdout.println("Ausgabe : " + line); stdout.print("Eingabe ? "); } } catch(Exception ex) { System.err.println("RMIFilterClient Exception : " + ex.getMessage()); ex.printStackTrace(); } }
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – A00 – 00 – TH – 01
-----------------------------------------------------------------------------------
Programmieren in Java
Anhang A
A. Modellierung von OOP-Programmen
A.1. Klassenkategorien A.2. Klassembeziehungen A.3. Klassendiagramm und Sequenzdiagramm der UML
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – A11 – 00 – TH – 05
-----------------------------------------------------------------------------------
Klassenkategorien
•••• Allgemeines
◇ Ein objektorientiertes Softwaresystem (OO-Programm) ist als eine Ansammlung interagierender Objekte organisiert.
◇ Die einzelnen Objekte decken dabei unterschiedliche Aufgabenbereiche ab. Entsprechend ihrem jeweiligen Aufgaben- bereich können sie und damit die sie beschreibenden Klassen unterschiedlichen Kategorien zugeordnet werden. � Objekte und Klassen besitzen einen Stereotype.
◇ Auch die gegebenenfalls zwischen Klassen bestehenden Beziehungen lassen sich in verschiedene Arten einteilen.
•••• Gebräuchliche Klassenkategorien
▻▻▻▻ Entity-Klassen Das sind Klassen, deren Objekte Bestandteil des Problembereichs sind (Domänen-Klassen). Sie reflektieren entweder reale Objekte des Problembereichs oder sie werden zur Wahrnehmung interner Aufgaben
des Systems benötigt. Es kann sich dabei um konkrete technische Objekte (z.B. Pkw) handeln, es können aber auch Personen und deren Rollen (z.B. Student, Kunde) Orte, (z.B.Hörsaal), Organisationseinheiten (z.B.Fachbereich), Ereignisse (z.B. Unfall), Informationen über (Inter-)Aktionen (z.B. Kaufvertrag), Konzepte (z.B. Entwicklungsplan), sonstige allgemeine oder problembereichsbezogene Begriffe (z.B.Lehrveranstaltung) usw. sein Objekte von Entity-Klassen sind typischerweise unabhängig von der Systemumgebung und von der Art und Weise, wie das System mit der Umgebung kommuniziert. Häufig sind sie auch applikationsunabhängig, d.h. sie lassen sich in mehreren Applikationen einsetzen.
▻▻▻▻ Interface-Klassen (Boundary Classes) Objekte dieser Klassen sind für die Kommunikation zwischen der Systemumgebung und dem Inneren des Systems zuständig. Sie realisieren die Schnittstelle des Systems zum Sytembenutzer (Benutzeroberfläche) bzw zu anderen Systemen. � Sie bilden den umgebungsabhängigen Teil eines Systems.
▻▻▻▻ Controller-Klassen (Control Classes) Objekte von Controller-Klassen steuern den Ablauf, d.h. die Zusammenarbeit der übrigen Objekte zur Realisierung eines oder mehrerer Use Cases. Es handelt sich um aktive Objekte. Typischerweise sind sie applikationsspezifisch.
▻▻▻▻ Service-Klassen Objekte von Service-Klassen stellen anderen Objekten (insbesondere den Controller-Objekten) Dienste zur Verfügung. Häufig handelt es um Klassen aus einer Bibliothek. Sie können aber auch durch Auslagerung von Funktionalitäten anderer Klassen gebildet werden.
▻▻▻▻ Utility-Klassen Sie kapseln Daten und Operationen (Funktionen), die global verfügbar sein sollen. Im allgemeinen werden sie nicht instanziiert. Beispiel : mathematische Konstanten u. mathematische Funktionen. Die konsequente Unterscheidung und Trennung von Entity-, Interface- und Controller-Klassen führt zur "Model-View-
Controller"-Architektur (MVC-Architektur), ein allgemein eingeführtes OOP-Paradigma. Das User-Interface (View) ist von der eigentlichen Problembearbeitung (Model) getrennt und weitgehend entkoppelt. Die Verbindung zwischen beiden wird über einen Controller hergestellt.
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – A21 – 00 – TH – 04
-----------------------------------------------------------------------------------
Beziehungen zwischen Klassen
•••• Vererbungsbeziehung
◇ Beziehung zwischen Klassen, deren Komponenten sich teilweise überdecken
◇ Eine abgeleitete Klasse erbt die Eigenschaften und Fähigkeiten (Komponenten) der Basisklasse(n). "ist"-Beziehung � ein Objekt der abgeleiteten Klasse ist auch ein Objekt der Basisklasse(n)
◇ Ordnungsprinzip bei der Spezifikation von Klassen. � Generalisierung / Spezialisierung •••• Nutzungsbeziehungen
◇ Unter einer (statischen) Nutzungsbeziehung versteht man eine in einem konkreten Anwendungsbereich geltende Beziehung zwischen Klassen, deren Instanzen voneinander Kenntnis haben und die dadurch miteinander kommuni-
zieren können � Nutzungsbeziehungen sind notwendig für die Interaktion von Objekten
◇◇◇◇ Assoziation - Spezielle Beziehung zwischen Klassen bzw Objekten, bei der die Objekte unabhängig voneinander existieren und lose miteinander gekoppelt sind Beispiel : einem Objekt wird ein anderes Objekt als Parameter übergeben. - Name : Kennzeichnung der Semantik der Beziehung zwischen den Klasseninstanzen - Navigationsrichtung : legt die Kommunikationsrichtung und die Richtung, in der ein Objekt der einen Klasse ein Objekt der anderen Klasse referieren kann, fest. bidirektional (Kommunikation in beiden Richtungen möglich) oder unidirektional - Rolle : Ein Name für die Aufgabe, die ein Objekt der assoziierten Klasse aus der Sicht eines Objekts der assoziie- renden Klasse wahrnimmt. - Kardinalität (multiplicity) : bezeichnet die mögliche Anzahl der an der Assoziation beteiligten Instanzen einer Klasse.
◇◇◇◇ Aggregation - Spezielle Beziehung zwischen Klassen bzw Objekten, bei der die Objekte der einen Klasse Bestandteile (Kompo- nenten) eines oder mehrerer Objekte der anderen Klasse sind. � zwischen den Objekten besteht eine feste Kopplung - "hat"-Beziehung bzw "ist Teil von"-Beziehung - Das "umschließende" Objekt bildet einen Container für das bzw die enthaltene(n) Objekt(e) - Aggregation kann als Spezialfall der Assoziation aufgefaßt werden. � die für Assoziationen möglichen Kennungen (Name usw.) lassen sich auch für Aggregationen verwenden. - eine Aggregation ist i.a. aber eine unidirektionale Beziehung (Navigation vom umschließenden Objekt zu den Kom- ponenten-Objekten) Je nach dem Grad der Kopplung unterscheidet man :
▻ einfache Aggregation Das umschließende Objekt (Aggregat) und die Komponenten sind nicht existenzabhängig
Eine Komponente kann zusätzlich noch weiteren Aggregaten der gleichen oder einer anderen Klasse zugeordnet sein. Bei Löschung des Aggregats bleiben die Komponenten unabhängig vom Aggregat erhalten. Beispiel : Klasse mit dynamisch erzeugten Komponenten
▻ echte Aggregation (Komposition, composite aggregation) Die Komponenten können nur einem Aggregat zugeordnet sein und nur innerhalb des Aggregats existieren. Bei Löschung des Aggregats werden auch die Komponenten gelöscht. Beispiel : Klasse mit statisch allozierten Komponenten
◇◇◇◇ Anmerkung : In der Praxis kann es im Einzelfall sehr schwierig sein, zwischen Assoziation und Aggregation und den verschiedenen Formen der Aggregation zu unterscheiden.
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – A31 – 00 – TH – 05
-----------------------------------------------------------------------------------
Modellierung
•••• Allgemeines
◇ Das zu entwickelnde Software-System sowie der von ihm abzudeckende Problembereich sind häufig so komplex, dass sie sich nur mit Hilfe geeigneter Hilfsmittel ausreichend erfassen lassen. Ein derartiges Hilfsmittel stellt die Modellierung dar.
◇ I.a. ist es wenig sinnvoll das Gesamtsystem in einem einzigen – alle Einzelheiten erfassenden – Modell darzustellen. Vielmehr setzt man unterschiedliche Modelle ein, die jeweils verschiedene Teilaspekte des Systems repräsentieren. Diese Modelle erleichtern nicht nur das Problembereichs- und Systemverständnis, sondern bilden auch ein wesentliches Kommunikationsmittel aller an der Systementwicklung beteiligten Personen und stellen damit auch einen wichtigen Bestandteil der Systemdokumentation dar.
◇ Voraussetzung für die Bildung adäquater, ausagekräftiger, eindeutiger und leicht verständlicher Modelle ist eine geeig-
nete Notation zur Modelbeschreibung. Für den Bereich der objektorientierten Systementwicklung ist dies die Unified Modeling Language (UML), mit der Mo delle in überwiegend graphischer Notation (� Diagramme) dargestellt werden können.
◇ Die UML stellt Sprachmittel zur Formulierung zahlreicher unterschiedlicher Diagramme zur Verfügung, die zur Beschreibung der verschiedenen Modelle geeignet sind.
• Modelle und zugeordnete UML-Diagramme
◇◇◇◇ Modell der Systemnutzung
▻▻▻▻ Nutzungsfallmodell (Anwendungsfallmodell) � Use-Case-Diagramm
◇◇◇◇ Logisches Modell
▻▻▻▻ Statisches Modell grobe Systemarchitektur (Aufbaustruktur) � Paketdiagramm detaillierte Systemarchitektur � Klassendiagramm
▻ Dynamisches Modell Zusammenarbeit mehrerer Objekte (Objekt-Interaktion) � Interaktionsdiagramme : Sequenzdiagramm
Kollaborationsdiagramm Objektverhalten (in mehreren Use Cases) � Zustandsdiagramm Systemverhalten � Aktivitätsdiagramm
◇◇◇◇ Physikalisches Modell
▻ Implementierungsmodell � Komponentendiagramm (Moduldiagramm)
▻ Konfigurierungsmodell � Verteilungsdiagramm (Deployment Diagram) (topologische Strukturierung und Verteilung/Zuordnung der Soft- und Hardwarekomponenten des Gesamtsystems)
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – A32 – 00 – TH – 05
-----------------------------------------------------------------------------------
Unified Modelling Language (UML) (1)
•••• Klassendiagramm
◇ Ein Klassendiagramm beschreibt die im System eingesetzten Klassen und ihre statischen Beziehungen (Vererbungs- beziehungen und Nutzungsbeziehungen).�detailliertes statisches Systemmodell
◇ Zur Erhöhung der Übersichtlichkeit kann die Gesamtheit der Klassen eines Systems auf mehrere Teildiagramme aufgeteilt sein • Elemente des Klassendiagramms
Klasse
Assoziation (bidirektional)
Vererbung
Assoziation (unidirektional)
Aggregation
Komposition (echte Aggregation)
Nam eOfClass
attribut : ty pe = initval
operation(argnam e : type) : re turnTy pe
M yS tring
M yS trM itF arbe
ClassBClass A
M yS tringCharF ilter
11 11
Tex tF ilterC trl CharFilt er
Order Task
1 1. .*1 1. .*
theRoleA
theRoleB
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – A33 – 00 – TH – 05
-----------------------------------------------------------------------------------
Unified Modelling Language (UML) (2)
• Beispiel für Klassendiagramme
Person
Projekt
Firma
*
1
*
Auftraggeber
1
Manager
1
*
1
*
Entwickler
1..* 1..*
1
*
1
*
2..n
1 1
2..n
Projektleiter
1 1
1
1TextFileReader
TextFileWriter
TextFilterCtrl
CharFilter
HOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – A34 – 00 – TH – 05
-----------------------------------------------------------------------------------
Unified Modelling Language (UML) (3)
•••• Sequenzdiagramm
◇ Ein Sequenzdiagramm beschreibt die Interaktion mehrerer Objekte.
◇ Für jedes Scenario jedes Use Cases sollte ein eigenes Diagramm erstellt werden.
•••• Beispiel für ein Sequenzdiagramm