Programmier

Werbung
IBIT - Angewandte Statistik
Manuskript
zu der Veranstaltung
PROGRAMMIEREN MIT JAVA
Es handelt sich bei dem Manuskript um internes Arbeitsmaterial, das nicht dazu geeignet ist, veröffentlicht zu werden. Es darf daher ohne Genehmigung des Verfassers in keiner Form (auch auszugsweise) reproduziert, vervielfältigt bzw. verbreitet oder in eine andere Sprache übersetzt werden.
 2005 Dr. Hans-Peter Bäumer, Carl von Ossietzky Universität Oldenburg, IBIT –
Angewandte Statistik, Postfach 2503, D-26111 Oldenburg
Email: [email protected]
Alle Rechte bleiben vorbehalten. Dieses Manuskript ist urheberrechtlich geschützt.
Programmieren mit Java
Einführung
1. Einführung
1.1
Grundfunktionen und typische Arbeitsschritte eines Compilers,
wesentliche Unterschiede zu einem Interpreter
1.2
Grundlegende Merkmale von Java
1.3
Verwandtschaftsbeziehungen von einigen (imperativen) Programmiersprachen im Überblick
1.4
Phasen in der Entwicklung objektorientierter Programme
1.5
Typographie
1
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers
Wie zu jeder imperativen Programmiersprache, so gehört auch zu
der rein objektorientierten Programmiersprache Java ein Compiler.
Die Kenntnis typischer Arbeitsschritte eines Compilers erleichtert
auch im Fall von Java erheblich die Entwicklung von Programmen,
die weniger fehleranfällig sind.
zwei Grundfunktionen eines Compilers
1. Grundfunktion
Ein Compiler ist ein Programm, das ein in der Quellsprache formuliertes Programm, das Quellprogramm, liest und in ein äquivalentes Programm einer anderen Sprache, das Zielprogramm, übersetzt.
2. Grundfunktion
Der Compiler hat als eine weitere wichtige Aufgabe, Warnungen
sowie Fehlermeldungen auszugeben, um den Programmierer bei
der Entwicklung eines fehlerfreien Quellprogramms zu unterstützen.
2
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers
Ein Compiler bewältigt einen wesentlichen Teil seiner Aufgaben in 3
Analyseschritten:
➘
der lexikalischen Analyse
➘
der syntaktischen oder hierarchischen Analyse
➘
der semantischen Analyse.
lexikalische Analyse
Zerlegung des zu verarbeitenden Zeichenstroms in Symbole
➘
Ein Symbol bezeichnet eine Zeichenfolge, der eine spezifische
Bedeutung zukommt.
Beispiel: Zeichenfolge quaderOf ist ein Name
Der Begriff Name wird noch festgelegt werden. Vorläufig
wird ein Name, wie quaderOf oder a, als ein Symbol aufgefasst werden, das dazu dient, einen Speicherbereich zu
identifizieren.
Von einem Compiler werden Namen üblicherweise erkannt, indem
die sequentielle Bearbeitung der Zeichen so lange fortgesetzt wird
bis ein Zeichen auftritt, dass in einem Namen unzulässig ist. Diese
Zeichenfolge wird aus dem Zeichenstrom eliminiert, zu einem Symbol zusammengefasst und ein Eintrag in der Symboltabelle vorgenommen.
3
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers
Diese zeichenorientierte Analyse ist im Allgemeinen nicht ausreichend, um in dem Zeichenstrom Ausdrücke oder Anweisungen
korrekt zu analysieren:
Beispiel: Korrespondenz von Klammern in einem Ausdruck
muss korrekt erkannt werden
Formel zur Berechnung der Oberfläche eines Quaders
Vorläufig wird jede endliche Sequenz von Ziffern des Dezimalsystems mit oder ohne Dezimalpunkt, wie 1.975302468 oder
12515, als Zahl aufgefasst. Die Begriffe Ausdruck und Zahl werden
noch präzisiert werden.
Daher ist es erforderlich, dem Zeichenstrom eine Struktur, beispielsweise eine hierarchische Struktur, zu unterstellen und eine
syntaktische oder auch hierarchische Analyse anzuschließen.
syntaktische Analyse
Zusammenfassen der Symbole, die in der lexikalischen Analyse ermittelt worden sind, zu grammatikalisch korrekten Sätzen
4
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers
In diesem Ausschnitt von Quellcode in Java sind
quaderOf, a, b und c Namen und 2.0 ist eine Zahl.
Für sich genommen bildet quaderOf=2.0*( keinen grammatikalisch korrekten Satz, denn die bei der lexikalischen
Analyse ermittelte Folge von Symbolen gehört nicht zu der
Menge der grammatikalisch korrekten Sätze.
semantische Analyse
Überprüfung von (grammatikalisch korrekten) Sätzen auf semantische Fehler:
➘
Überprüfung, ob die Datentypen von Operanden in einem Ausdruck verträglich sind
➘
Überprüfung, ob die Gültigkeitsbereiche von Namen eingehalten werden
Anschaulich formuliert ist der folgende Satz zwar syntaktisch korrekt, nicht jedoch semantisch:
Der Computer denkt.
5
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers
statische semantische Analyse
Die semantische Analyse zur Compilationszeit wird als statisch bezeichnet. Nicht alle semantischen Regeln einer Programmiersprache lassen sich zur Compilationszeit überprüfen.
Abbildung aus Aho, A.V., Sethi, R. & Ullmann, J.D. (1988): Compilerbau. Teil 1.
Bonn etc.: Addison-Wesley, S. 12
6
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers,
wesentliche Unterschiede zu einem Interpreter
Interpreter
Anstatt ein Quellprogramm in Zwischencode zu übersetzen und
daraus ein Objektprogramm zu generieren, das auf dem jeweiligen
Zielrechner ausführbar ist, übersetzt ein Interpreter jede Anweisung
des Quellcodes und veranlasst, dass die damit verbundenen Operationen direkt ausgeführt werden. Ein Interpreter erzeugt demnach
im Gegensatz zu einem Compiler keinen speicherbaren Maschinencode, also kein Objektprogramm.
Die Ausführung eines Programms, das in einer Interpretersprache
kodiert worden ist, nimmt in der Regel mehr CPU-Zeit in Anspruch
als die Ausführung eines funktional gleichen Programms in einer
Compilersprache.
Interpreter werden häufiger dann eingesetzt, wenn in einer Kommandosprache kodierte Anweisungen zu übersetzen und auszuführen sind. Typisch ist dann, dass jede Operation damit verknüpft ist,
ein komplexes Programm zu aktivieren, wie beispielsweise einen
Editor.
Java nimmt eine Zwischenstellung ein.
Java-Compiler
Von einem Java-Compiler (in der engeren Bedeutung des Begriffs)
wird ein portierbarer Zwischencode erzeugt. Eigenschaften des
Zielbetriebssystems
werden
nicht
berücksichtigt.
Dieser
Zwischencode wird als Bytecode bezeichnet.
7
Programmieren mit Java
1.1 Grundfunktionen und typische Arbeitsschritte eines Compilers,
wesentliche Unterschiede zu einem Interpreter
Optimierung des Zwischencodes
In der Regel dient ein Schritt in der Erzeugung von Zwischencode
zur Codeoptimierung. Damit wird vorbereitet, schließlich einen effizienteren Maschinencode zu generieren. Der Aufwand, der zur Optimierung des Zwischencodes betrieben wird, kann zwischen verschiedenen Compilern sehr unterschiedlich ausfallen.
Da Java Bytecode ein portierbarer Zwischencode ist, entfällt eine
maschinenspezifische Optimierung.
Java Virtual Machine (JVM)
Java Bytecode lässt sich auch auffassen als binärer Code in einer
portierbaren Maschinensprache für eine CPU Architektur, die als
Java Virtual Machine (JVM) bezeichnet wird. In der Regel wird die
JVM als Software implementiert, die Bytecode interpretiert. Viele
Implementationen der JVM verfügen über just-in-time (JIT) Interpreter, die Java Bytecode direkt in Maschinenbefehle des jeweiligen
Zielbetriebssystems übersetzen.
Die Ausführungszeit des von Byte- in den Maschinencode des jeweiligen Zielrechners überführten Programms soll sich (nach Herstellerangaben) nur geringfügig von der Ausführungszeit eines Objektprogramms unterscheiden, dessen Quellcode in C++ kodiert
worden ist.
8
Programmieren mit Java
1.2 Grundlegende Merkmale von Java
Vom Quellcode zur Klasse, die unter der JVM startbar ist
nach Heinisch, C., Müller, F. & Goll, J. (2005): Java als erste Programmiersprache.
Vom Einsteiger zum Profi. Stuttgart etc.: Teubner, S. 63
9
Programmieren mit Java
1.2 Grundlegende Merkmale von Java
10
Neben der Programmiersprache Java und der JVM ist ein weiteres
grundlegendes Merkmal von Java die Java Plattform.
Java Plattform
Eine Plattform wird definiert durch das API (application programming interface), auf das vom Softwareentwickler zurückgegriffen
werden kann, um ein lauffähiges Programm zu codieren. Das jeweilige API wird in der Regel durch das Betriebssystem des Zielrechners festgelegt.
Um in einer imperativen Programmiersprache das gleiche Programm unter MS Windows XP, Solaris Version 10 oder einem Unixbasierten Betriebssystem zu entwickeln, verwendet der Softwareentwickler 3 unterschiedliche APIs. In diesem Sinne sind MS Windows, Solaris und Linux als 3 verschiedene Plattformen zu verstehen.
Eine Anwendung, die auf einer Java Plattform entwickelt worden ist,
läuft unter jedem Betriebssystem, von dem diese Java Plattform unterstützt wird. Dabei sollte eine Java Plattform jedoch nicht als Betriebssystem missverstanden werden. Eine Java Plattform ist eine
vordefinierte Menge von Klassen, die mit Java zur Verfügung gestellt und die auch als Java Klassenbibliothek bezeichnet wird.
Eine Klasse ist eine Einheit von Java Quellcode, mit der eine Datenstruktur definiert und dazu eine Menge von Methoden bereitgestellt wird, die auf dieser Datenstruktur operieren. Der Begriff Klasse
wird im Folgenden noch präzisiert und Klassen werden ausführlich
behandelt werden.
Eng verwandte Klassen werden unter Java zu Paketen zusammengefasst. Auch der Begriff Paket wird im Folgenden noch präzisiert
und Pakete werden ausführlich behandelt werden.
Programmieren mit Java
1.2 Grundlegende Merkmale von Java
11
Die Java 1.2 Plattform wird wegen ihrer bedeutenden Erweiterungen auch als Java 2 Plattform oder genauer als Java 2 Software
Development Kit, Standard Edition (J2SE), Version 1.5, bezeichnet
und umfasst eine Vielzahl von Klassen, die in 166 Paketen zusammengefasst sind. Das folgende Diagramm veranschaulicht den konzeptionellen Aufbau einer J2SE Plattform.
Die Java Klassenbibliothek setzt sich zusammen aus der
Java Base API
Java Standard Extension API.
Die 13 mit java eingeleiteten (Haupt-)Pakete der Java Base API
werden im Folgenden kurz vorgestellt.
Programmieren mit Java
1.2 Grundlegende Merkmale von Java
12
java.applet
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der Codierung von Applets zu unterstützen. Ein Applet ist ein Java
Programm, das in eine Webseite integriert ist, heruntergeladen und
auf dem Client-Rechner ausgeführt wird.
java.awt
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der Codierung plattformunabhängiger Anwenderoberflächen und
von grafischen Darstellungen zu unterstützen. Dabei steht awt als
Abkürzung für abstract window toolkit.
java.beans
Dieses Paket stellt Klassen bereit, um den Programmierer bei der
Entwicklung von Komponenten unter Java zu unterstützen. Dabei
steht beans als Bezeichnung für Komponenten des Komponentenmodells unter Java.
java.io
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der Codierung von Ein-Ausgabe Operationen zu unterstützen. Dabei steht io als Abkürzung für input output.
java.lang
Dieses Paket stellt Klassen bereit, um den Programmierer bei der
Entwicklung von Java Quellcode zu unterstützen. Dabei steht lang
als Abkürzung für language.
java.math
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der Codierung von numerisch hochgenauen Algorithmen zu unterstützen. Dabei steht math als Abkürzung für mathematics.
Programmieren mit Java
1.2 Grundlegende Merkmale von Java
13
java.net
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der netzwerkzentrierten Programmierung zu unterstützen. Dabei
steht net als Abkürzung für networking.
java.nio
Dieses Paket stellt Klassen bereit, die dazu dienen, die Ein- und
Ausgabe großer Datenmengen besser zu unterstützen. So wird zu
jedem einfachen Datentyp eine Klasse zum gepufferten Lesen und
Schreiben großer Datenmengen bereitgestelt. Dabei steht nio als
Abkürzung für new input output.
java.rmi
Dieses Paket stellt Klassen bereit, die dazu dienen, Schnittstellen
zu identifizieren, um deren Methoden von einer nichtlokalen JVM
aufrufen zu können. Dabei steht rmi als Abkürzung für remote
method invocation.
java.security
Dieses Paket stellt Klassen bereit, um die Softwareentwicklung
nach dem Java Sicherheitskonzept zu unterstützen. Dabei steht
security als Bezeichnung für dieses Sicherheitskonzept.
java.sql
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der Programmierung des Zugriffs auf Datenbanken zu unterstützen.
Dabei steht sql als Abkürzung für structured query language.
java.text
Dieses Paket stellt Klassen bereit, um den Softwareentwickler bei
der (sprachunabhängigen) Formatierung von Datumsangaben, Uhrzeit und weiteren Textbestandteilen zu unterstützen.
Programmieren mit Java
1.2 Grundlegende Merkmale von Java
14
java.util
Dieses Paket stellt eine Kollektion von Klassen bereit, die in unspezifischer Bedeutung Hilfsmittel für die Programmierung sind. Dabei
steht util als Abkürzung für utilities.
Über die Pakete der Java Base API hinaus wird die Java Plattform
durch die Pakete der Java Standard Extension API erweitert. Diese
Pakete sind als echte Erweiterung in dem Sinne zu verstehen, dass
sie in der Regel nicht mit der SDK ausgeliefert werden. Als Beispiel
sei die Java Telephony API (JTAPI) erwähnt.
Hauptanwendungsgebiete
Hauptanwendungsgebiete von Java sind die Entwicklung von
Applets, von plattformunabhängigen Anwendungen, von Serveranwendungen (Servlets), von Anwendungen auf Handys oder ähnlichen mobilen Geräten (MIDlets) und von ’Server-Seiten’ (Java Server Pages), um dynamisch Internetseiten generieren zu lassen.
Integrierte Entwicklungsumgebung
Integrierte Entwicklungsumgebungen dienen dazu, den Programmierer bei der Softwareentwicklung in einer Programmiersprache zu
unterstützen. Sie umfassen unter Java neben Compiler und Java
Plattform weitere Softwarekomponenten, wie einen Debugger und
einen spezifischen Editor, um Quellcode zu erfassen und komfortabel korrigieren zu können, und bieten ferner Werkzeuge zur Verwaltung von Softwareprojekten an.
Borland JBuilder 2005 Developer versteht sich als eine integrierte
Entwicklungsumgebung für Software, die in Java codiert wird.
15
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
In den Anfängen der EDV war das Erstellen eines Programms
äußerst mühsam und sehr zeitaufwendig:
➘
Programme wurden in Maschinensprache, später auch in
Assembler kodiert.
➘
Die Umwandlung in Maschinensprache erfolgte durch Programme.
Eine wesentliche Voraussetzung dafür, ein lauffähiges Programm
zu erstellen, waren weitreichende Kenntnisse der Eigenschaften der
Hardware.
Der überwiegende Anteil an den Kosten des Betriebs einer Rechenanlage entfiel auf den Bereich Programmierung und Korrektur von
Programmierfehlern.
erstes Abstraktionsniveau
Formulierung von Ausdrücken als Quellcode ohne direkt auf Maschinenregister zugreifen zu müssen
Eine Arbeitsgruppe der IBM entwickelte Ende 1953 die erste höhere
Programmiersprache:
➘
FORTRAN (FORmula TRANslation)
16
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Die Verfügbarkeit einer höheren Programmiersprache bedeutete
eine weitreichende Innovation:
➘
Nicht nur Computerexperten, sondern auch andere Wissenschaftler und Ingenieure erhielten Zugang zu den Leistungen
von Rechenanlagen.
➘
Ein Programmierer musste nicht mehr in erster Linie Eigenschaften der Hardware kennen und berücksichtigen, sondern
konnte sich auf die softwareseitigen Aspekte einer Problemlösung konzentrieren.
Seither haben sich weitere imperative Programmiersprachen etabliert.
zweites Abstraktionsniveau
Kontrollstrukturen und Paradigma des strukturierten Programmierens
Algorithmus
Algorithmus im engeren Sinn bezeichnet eine Rechenvorschrift. Allgemeiner schreibt ein Algorithmus vor, welche Handlungen in welcher Reihenfolge auszuführen sind, um ein angestrebtes Resultat
zu erreichen.
Prozessor
Um einen Algorithmus auszuführen, um das angestrebte Ziel zu erreichen, bedarf es eines Hilfsmittels, eines ausführenden ‘Organs‘,
im engeren Sinne eines Prozessors.
17
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Beispiel aus dem Alltag für einen Algorithmus: Kochrezept
Beispiel aus dem Alltag für einen Prozessor: Koch
Merkmale, die einen Algorithmus charakterisieren
➘
eine Menge von Objekten, die nach einer Vorschrift zu bearbeiten sind
➘
eine Menge von Operationen, die auf den Objekten auszuführen sind
➘
einen Anfangszustand, in dem sich die Objekte befinden, bevor sie bearbeitet werden
➘
einen Endzustand, in dem sich die Objekte befinden, nachdem
sie entsprechend der Vorschrift bearbeitet worden sind
In einem Programm, das in einer Programmiersprache formuliert ist,
muss im Unterschied zu einem Kochrezept jede Anweisung an das
ausführende Organ, den Prozessor, explizit und eindeutig angegeben sein.
Sequentielle und parallele Ausführung von Anweisungen
Im einfachsten Fall werden die Anweisungen, die ein Programm an
den bestimmten Prozessor enthält, sequentiell abgearbeitet, also in
der Reihenfolge, die im Programm vorgegeben ist.
18
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Werden Anweisungen, die ein Programm enthält, gleichzeitig von
mehr als einem Prozessor arbeitsteilig ausgeführt, liegen parallele
Betriebssystem-Prozesse vor.
Quasi parallele Prozesse
Prozesse können innerhalb eines Betriebssystem-Prozesses auch
quasi parallel ablaufen. Dabei bezeichnet quasi parallel den Fall, in
dem mehrere Prozesse in einer spezifischen Reihenfolge sequentiell von einem Prozessor ausgeführt werden. Beispielsweise werden innerhalb eines Server-Betriebssystem-Prozesses verschiedene Anwenderanfragen quasi parallel abgearbeitet. Solche Prozesse werden im Angelsächsischen als ’Threads’ bezeichnet und im
Folgenden noch ausführlich behandelt werden.
Kontrollfluss
Die Reihenfolge der Ausführung von Anweisungen wird als Kontrollfluss bezeichnet.
Kontrollstruktur
Eine Anweisung, mit der die Reihenfolge der Ausführung von Anweisungen beeinflusst wird, heißt Kontrollstruktur.
Wird von einem ausschließlich sequentiellen Programmablauf ausgegangen, dann umfasst eine imperative Programmiersprache Kontrollstrukturen für die
➘
Selektion
➘
Iteration
➘
Sequenz.
19
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Sequenz und Block
Sequenz beschreibt vereinfachend, dass Anweisungen in der Reihenfolge bearbeitet werden, in der sie im Programm angegeben
sind. Jede Anweisung einer Sequenz wird auch als sequentielle Anweisung bezeichnet. Die Kontrollstruktur für die Sequenz ist der
Block.
Sequentielle Anweisung
Eine sequentielle Anweisung ist dadurch charakterisiert, dass sie
nur über die unmittelbar vorangehende Anweisung zugänglich ist
und ihr einziger Ausgang in die unmittelbar folgende Anweisung
führt.
Kontrollstrukturen werden im Folgenden noch ausführlich behandelt
werden.
Beispiel für Iteration und Selektion: Euklidscher Algorithmus
zur Bestimmung des ggT von 2 natürlichen Zahlen
Bezeichne x eine natürliche Zahl wie auch y . Solange x ≠ y
gilt, wiederhole die folgenden Operationen (Iteration): Falls
x < y , berechne y − x und weise das Ergebnis y zu. Andernfalls berechne x − y und weise das Ergebnis x zu
(Selektion).
Ist der Wert von x identisch mit dem Wert von y , dann geben x wie y den Wert des ggT an.
20
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Der Euklidsche Algorithmus zur Berechnung des ggT von 2 natürlichen Zahlen wird demnach charakterisiert durch:
➘
die zweielementige Menge von Objekten {x, y} , wobei
o.B.d.A. x ≠ y vorausgesetzt wird
➘
die Menge von Operationen { =, ! =, <, −} . Dabei bezeichnet
= den einfachen Zuweisungsoperator, ! = den Ungleichheitsoperator, < den Kleiner-als-Operator und − den arithmetischen Operator für die Subtraktion.
Damit ist der Algorithmus jedoch noch nicht vollständig charakterisiert. Anfangs- und Endzustand sind noch zu beschreiben.
Anfangszustand: Variablen und ihre Initialisierung
Um die Ausführung des Algorithmus für 2 beliebige natürliche Zahlen realisieren zu können, werden 2 Variablen, x und y , eingeführt.
Die Ausführung des Algorithmus beginnt damit, dass diesen Variablen Anfangswerte zugewiesen werden. Unter imperativen Programmiersprachen werden Speicherbereiche, auf die Schreibzugriff zulässig ist, auch als Variablen bezeichnet. Die Zuweisung eines Anfangswerts an eine solche Variable heißt auch Initialisierung.
Auf die Begriffe Variable und Initialisierung wird im Folgenden noch
ausführlich eingegangen werden.
Endzustand
21
Der gewünschte Endzustand der Variablen x und y wird so
festgelegt, dass x = = y gilt, wobei = = den Gleichheitsoperator
bezeichnet.
22
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Strukturierte Programmierung
Ein Programm, in dem ausschließlich Kontrollstrukturen mit der Eigenschaft einer sequentiellen Anweisung eingesetzt werden, unterliegt den Regeln der strukturierten Programmierung.
drittes Abstraktionsniveau
Klassen (abstrakte Datentypen) und Paradigma des objektorientierten Programmierens
Zentrale Begriffe auf der Ebene der Sprachstrukturen sind
➘
Klasse oder abstrakter Datentyp
➘
abgeleitete Klasse und Klassenhierarchie
➘
polymorphe Operation.
Klasse
Klasse bezeichnet einen abgeschlossenen Baustein, der sowohl die
zugehörigen Datenkomponenten, die Verfahren zum Zugriff auf
diese Datenkomponenten als auch die zugehörigen Algorithmen
umfasst. Die Trennung von Daten und Algorithmen wird aufgehoben. Unter Java bildet eine Klasse eine Einheit aus Datenkomponenten und der Definition von Funktionen, die auch als Methoden
bezeichnet werden. Datenkomponenten und Methoden einer Klasse
werden auch als ihre Elemente bezeichnet.
Dieses Merkmal wird auf konzeptioneller Ebene als Datenkapselung bezeichnet.
23
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Datenkomponenten, die zu einer Klasse gehören, dienen dazu, die
Informationen zu beschreiben, die zu dieser Klasse gehören. Eine
Datenkomponente ist im Wesentlichen die Deklaration einer Variablen.
Methoden beschreiben die Fähigkeiten, die zu einer Klasse gehören. Eine Methode ist im Wesentlichen die Definition einer Funktion.
abgeleitete Klasse, Klassenhierarchie
Von einer Klasse lassen sich weitere Klassen ableiten. Eine abgeleitete Klasse übernimmt (erbt) die Datenkomponenten und Methoden ihrer Elternklasse. Ausgehend von einer Basisklasse kann eine
Hierarchie aus Eltern- und Kindklassen aufgebaut werden.
Dieses Merkmal wird auf konzeptioneller Ebene als Vererbung bezeichnet.
polymorphe Operation
Wenn zu einer Operation mehrere Methoden in unterschiedlichen
Klassen mit gleichem Namen und identischer Schnittstelle existieren, wird eine solche Operation als polymorph bezeichnet. Demnach stimmt die Deklaration einer Methode in einer Klassenhierarchie überein, wobei jede Klasse in der Hierarchie diese Methode in
einer für sich geeigneten Art und Weise implementiert. Beispiel für
eine polymorphe Operation ist das Verschieben einer ebenen geometrischen Figur auf dem Bildschirm.
Im Kontext von Sprachkonzepten heißt dieses Merkmal Polymorphismus.
24
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
Beispiel für eine Klasse Ggt : Euklidscher Algorithmus zur
Bestimmung des ggT von 2 natürlichen Zahlen
Die Klasse Ggt verfügt über zwei Datenkomponenten, x
und y , von geeignetem Datentyp. Ferner hat die Klasse
einen Konstruktor, um x und y zu initialisieren. Die Klasse
wird über eine Methode verfügen, um den Wert von x zu
setzen, über eine weitere Methode, um den Wert von y zu
setzen, über eine Methode, um den Wert von x zu lesen
sowie über eine Methode, um den Wert von y zu lesen.
Schließlich wird zu der Klasse eine Methode gehören, die
dazu dient, den ggT von x und y nach dem Euklidschen
Algorithmus zu bestimmen.
Wird eine Klasse von der Klasse Ggt abgeleitet, dann
verfügt die abgeleitete Klasse über die Datenkomponenten
und Methoden der Elternklasse, also beispielsweise über eine
Methode, um den ggT von x und y nach dem Euklidschen
Algorithmus zu bestimmen.
Klassen, abgeleitete Klassen, der Aufbau von Klassenhierarchien
und polymorphe Operationen werden im Folgenden noch ausführlich behandelt werden.
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
24
25
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
(1)
1954 - 57 FORTRAN (FORmula TRANslation)
Programmiersprache für technisch-naturwissenschaftliche Anwendungen
(2)
1959 - 60 COBOL (COmmon Business Oriented Language)
Programmiersprache für kaufmännische Anwendungen zur Verarbeitung
umfangreicher Datenmengen
(3)
1958 - 60 ALGOL 60 (ALGOrithmic Language)
Programmiersprache für mathematisch-naturwissenschaftliche Anwendungen
(4)
1963 - 64 PL/1 (Programming Language 1)
Programmiersprache, die aus ALGOL-, COBOL- und FORTRAN-Elementen
entwickelt wurde mit dem Ziel, eine einheitliche Programmiersprache sowohl
für den kommerziellen und als auch den technisch-wissenschaftlichen Bereich
zu schaffen
(5)
1962 - 67 SIMULA
Programmiersprache, die ursprünglich entworfen worden ist, um Software zur
Simulation diskreter Ereignisse zu entwickeln und die einen ausgeprägten Einfluss auf die Weiterentwicklung von Programmiermethoden genommen hat
(6)
1963 - 68 ALGOL 68
Weiterentwicklung von ALGOL 60
(7)
1968 - 71 Pascal
Programmiersprache, die strukturiertes Programmieren konzeptionell unterstützt und in der Ausbildung favorisiert wurde
(8)
1969 BCPL (Basic Combined Programming Language)
Programmiersprache, mit der die Struktur von ALGOL und die Leistungsfähigkeit von Assembler kombiniert werden
(9)
1970 - 72 Smalltalk
rein objektorientierte Programmiersprache, die u.a. auf Simula und LISP basiert und sich durch ihre Einfachheit auszeichnet
(10) 1973 - 78 C
Programmiersprache, die blockstrukturiertes Programmieren unterstützt und
hardwarenahes Programmieren erlaubt
26
Programmieren mit Java
1.3 Verwandtschaftsbeziehungen einiger (imperativer) Programmiersprachen im Überblick
(11) 1977 - 80 Modula
Programmiersprache, die auf Pascal basiert, weitgehend maschinenunabhängig
ist und Konzepte der Softwaretechnik unterstützt, wie Modularisierung
(12) 1977 - 80 Ada
Programmiersprache, die für eingebettete Systeme entwickelt worden ist, und
vor allem in Anwendungsbereichen mit hohen Sicherheitsanforderungen
(u.a. kommerzielle Luftfahrt, US Verteidigungsministerium) eingesetzt wird
(13) 1980 - 1983 C++
Weiterentwicklung der Programmiersprache C zu einer hybriden Programmiersprache, mit der objektorientiertes Programmieren unterstützt wird
(14) 1995 Java
rein objektorientierte Programmiersprache mit einer C++-ähnlichen Syntax,
aus der portierbarer Bytecode generiert wird und von der die Entwicklung von
Applets, Servlets, MIDlets und ’Server-Seiten’ unterstützt wird
Einführende Informationen zu einer Auswahl höherer Programmiersprachen wird unter der folgenden URL angeboten:
http://www.engin.umd.umich.edu/CIS/course.des/cis400
Programmieren mit Java
1.4 Phasen in der Entwicklung objektorientierter Programme
27
1.4 Phasen in der Entwicklung objektorientierter Programme
Phase 0: Kernaufgabe der zu entwickelnden Software
grundlegende Leistung
Phase 1: Anforderungsanalyse und Zusammenstellung der Anwendungsfälle (Gesamtmenge an Szenarien)
Ein Anwendungsfall ist eine Aktion zwischen einem System
und einem Akteur (einer Person, einem anderen Rechnersystem)
Bestimmung der Akteure
Bestimmung der möglichen (zulässigen) Aktionen
Wie übt ein Akteur eine Aktion aus?
Varianten des Agierens
Probleme, Ausnahmen
Programmieren mit Java
1.4 Phasen in der Entwicklung objektorientierter Programme
28
Leffingwell, D. & Widrig, D. (2003): Managing Software Requirements: A Use Case
Approach. The Addison-Wesley Object Technology Series. Reading etc.:
Addison-Wesley Professional, 2nd ed.
Schneider, G. & Winters, J.P. (2001): Applying Use Cases: A Practical Guide. Amsterdam etc.: Addison-Wesley Longman, 2nd ed.
Seemann, J. & Gudenberg, J. W. v. (2004): Software-Entwurf mit UML. Objektorientierte Modellierung mit Beispielen in Java, Berlin etc.: Springer, 2., überarb.
Aufl.
Phase 2: Grobdesign
Beschreibung der Klassen und insbesondere der Schnittstellen der Methoden der jeweiligen Klasse
Eine Klasse ist, wie bereits angedeutet, eine vom Programmierer definierte Datenstruktur, die, um eine spezifische Aufgabe zu behandeln, gemeinsame Datenkomponenten, Methoden zum Zugriff auf diese Datenkomponenten und gemeinsame Funktionalitäten zusammenfasst.
Zaehler
Klassenname
zaehlerstand
Datenkomponente
setze_zaehlerstand
Methoden
ermittle_zaehlerstand
bereinige_zaehlerstand
erhoehe_zaehlerstand
reduziere_zaehlerstand
Programmieren mit Java
1.4 Phasen in der Entwicklung objektorientierter Programme
29
Die zu jeder spezifischen Aufgabe gehörige Datenstruktur
wird auf eine Klasse abgebildet.
Jede Klasse sollte möglichst einfach aufgebaut sein.
Jede dieser Klassen wird sich im Verlauf der Arbeit am Grobdesign weiterentwickeln. Der Anspruch, bereits zu Beginn
der Phase 2 jede Klasse vollständig zu spezifizieren, erweist
sich in der Regel als zu restriktiv.
Erste kompilierbare Quellcodeanteile werden formuliert, um
die Leistungsfähigkeit und den Leistungsumfang einzelner
Klassen zu überprüfen.
Phase 3: Entwicklung des Kerns des Zielprogramms
Übertragung des Grobdesigns in kompilier- und ausführbaren Quellcode, um das Grobdesign im Abgleich zu dem Resultaten aus der Phase 1 auf seine Tragfähigkeit zu überprüfen
Es wird eine erste, in der Regel unvollständige Fassung des
Zielprogramms entwickelt, so dass sich ausführbarer Code
generieren lässt.
Kritische Leistungsmerkmale werden herausgearbeitet und
im Quellcode lokalisiert.
Aus den Erfahrungen, die mit dieser ersten Fassung des Zielprogramms gesammelt werden, resultiert in der Regel eine
Weiterentwicklung des Grobdesigns.
Insgesamt handelt es sich bei der Phase 3 um einen ersten
Schritt der Programmentwicklung in einer Sequenz von
Schritten, also um die Entwicklung eines Rahmens, der in der
Phase 4 ausgefüllt wird.
Programmieren mit Java
1.4 Phasen in der Entwicklung objektorientierter Programme
30
Phase 4: Iteration
Einfügen weiterer begrenzter Teilprojekte in den bereits entwickelten Rahmen, um die Funktionalität des bestehenden
Programms in Richtung auf das Zielprogramm zu erweitern
Die Grundlage für jeden Iterationsschritt bildet ein weiterer
Anwendungsfall, der in das bestehende Programm integriert
wird. Dabei ist jeder Anwendungsfall als ein Bündel
untereinander verknüpfter Funktionalitäten zu verstehen.
Ein besonderer Vorteil dieser Vorgehensweise besteht darin,
dass sich nach jedem Iterationsschritt der Status des
bestehenden Programms direkt bestimmen lässt.
Die Phase 4 wird beendet, wenn das entwickelte Programm
die postulierten Funktionalitäten (möglichst) fehlerfrei erbringt.
Phase 5: Evolution
Übergang in eine Phase fortwährender Modifikation des Programms nach Abschluss des primären Entwicklungszyklus
Aus den Tests des bestehenden Programms und aus seinen
praktischen Anwendungen erwächst ein tieferes Verständnis
für die zu bewältigenden Aufgaben und für den internen Aufbau des Quellcodes. Daraus resultieren Modifikationen des
bestehenden Programms, die sukzessive zu leicht verständlichem und eleganterem Quellcode wie auch zur verbesserten
Funktionalität führen sollten.
Einer der Hauptvorteile objektorientierten Programmierens
besteht darin, dass Modifikationen des jeweiligen Programms
für den (die) Programmierer eine vergleichsweise leicht zu
bewältigende Aufgabe ist.
Programmieren mit Java
1.5 Typographie
31
1.5 Typographie
Schriftarten, Schreibweisen und Metasymbole
Eine vollständige und formal exakte Beschreibung der Syntax der
Programmiersprache Java in einer Metasprache ist im Kontext der
Veranstaltung nicht vorgesehen.
Um die Lesbarkeit des Texts zu verbessern und um inhaltliche Bezüge zu verdeutlichen, werden unterschiedliche Schriftarten und
Darstellungsformen verwendet.
Beispiele, auch (auszugsweise) Programmbeispiele, und die Syntax der Programmiersprache Java werden in der Schriftart
Courier dargestellt und stets in einen Rahmen gesetzt.
Auszüge aus Beispielen und Bezeichnungen der Syntax im Text
werden ebenfalls in Courier dargestellt.
Kommentare im Quellcode und literale Zeichenkonstanten werden in der üblichen Groß-Kleinschreibweise formuliert.
Auch einige syntaktische Metasymbole werden im Folgenden eingeführt werden.
Eine optionale Angabe in der Syntax wird kursiv gesetzt werden.
Eine optional zu wiederholende Angabe angabe wird durch das
Metasymbol angabe... beschrieben werden. Dabei schließt
angabe... den Fall mit ein, dass angabe nicht wiederholt wird.
Wird ein Begriff festgelegt, so wird er in der charakterisierenden
Beschreibung fett und kursiv gesetzt.
Herunterladen