Skript

Grundlagen der Datenverarbeitung II
Version Jun 20, 2003
SS 03 Prof. Dr. Sven Eric Panitz
TFH Berlin
Der Inhalt dieses Skriptes wurde im Laufe der Vorlesung im WS2002/03 entwickelt. Das Skript entstand zur Vorbereitung auf das SS03.
Der Quelltext dieses Skripts ist eine XML-Datei, die durch eine XQuery in eine LATEX-Datei transformiert und für die schließlich eine pdf-Datei und eine postscript-Datei erzeugt wird. Der XML-Quelltext verweist direkt auf ein XSLT-Skript, daß eine HTML-Darstellung erzeugt, so daß ein entsprechender Browser mit XSLT-Prozessor die XML-Datei direkt als HTML-Seite darstellen kann.

Chapter 1
Einführung

1.1  Ziel der Vorlesung

Diese Vorlesung soll über die Benutzung des Computers mit den gängisten Werkzeugen hinausgehen und sich mit den Interna hinter den Kulissen beschäftigen. Hierzu wird ein Einblick in die Programmierung gegeben. Ziel ist nicht, eine komplette Programmierausbildung zu geben (was in einer einsemestrigen zweistündigen Vorlesung auch nicht möglich wäre), sondern mit den Grundprinzipen der Programmierung vertraut zu machen. Hierzu gibt es zwei Hauptkapitel:
In den Übungen wird der Umgang mit der Kommandozeile und die Benutzung von Kommandozeilenprogrammen erlernt.
Es werden in dieser Vorlesung keine speziellen Werkzeuge oder Anwendungsprogramme vorgestellt.

1.2  Betriebssysteme

Der Rechner, der auf unseren Schreibtisch steht, ist unsere Hardware. Er besteht in der Regel aus einem Prozessor, Hauptspeicher, einer Festplatte und eine Reihe von Peripheriegeräten zur Ein- und Ausgabe wie Bildschirm, Tastatur, Maus, Drucker, Scanner, Modem etc.
Wir wollen uns dem Computer mit der Sicht eines Programmierers nähern. Hierzu machen wir uns zunächst ein wenig mit der Funktionsweise des Rechners vertraut:
Wenn wir den Computer anschalten, so ist er so konstruiert, daß er auf verschiedenen Betriebsmitteln nach einem ladbaren Programm sucht; dieses Programm ist das Betriebssystem. In der Regel findet er auf der Festplatte das Betriebssystem und startet dieses.
Ein Betriebssystem ist also nichts weiter als ein Programm. Dem Computer als Hardware ist egal, was das Betriebssystem als Software für ein Programm ist. Für ihn ist es lediglich eine Folge von Nullen und Einsen, die Befehle für seinen Prozessor darstellen. Wenn das Betriebssystem gestartet wird, so wird diese Folge von Nullen und Einsen in den Hauptspeicher geladen und nach und nach dem Prozessor als Befehle gegeben.
Dem Prozessor ist egal, was für Befehle er ausführt. Theoretisch könnten wir auf der Festplatte ein Programm als Betriebssystem installieren, das nicht die Funktionalität eines Betriebssystems hat, sondern z.B. ein Computerspiel ist.1

1.2.1  Aufgaben eines Betriebssystems

Was sind die Aufgaben eines Betriebssystems. Diese Frage ist nicht pauschal zu beantworten und in gewisser Weise eine Definitionsfrage, manchmal sogar eine juristische Frage. Gehört zu einem Betriebssystem eine graphische Benutzeroberfläche? Was sind noch die Aufgaben des Betriebssystems und was ist Anwendungssoftware? Gehört zu einem Betriebssystem ein Webbrowser? Diese Ansicht vertrat die Firma Microsoft als sie ihren Webbrowser Internet Explorer zu einem integralen Bestandteil des Betriebssystems Windows machen wollte. Die Firma Netscape, deren Hauptprodukt ein Webbrowser war, klagte gegen diese Ansicht.
Die Hauptaufgabe eines Betriebssystems ist, Betriebsmittel zu verwalten und Programme zu starten. Alle weiteren Aufgaben, wie z.B. eine graphische Benutzeroberfläche, Benutzerverwaltung, nebenläufige Programmausführung usw. sind im Prinzip schon Luxus.
Von einem minimalen Betriebssystem sollte erwartet werden, daß es ein Eingabegerät (die Tastatur) und ein Ausgabegerät (den Bildschirm) steuert, ein Dateisystem auf der Festplatte verwalten kann und die Möglichkeit hat, Anwendungsrogamme zu starten.
Wenn das Betriebssystem läuft und den Benutzer erlaubt z.B.  über die Kommandozeile ein Anwendungsprogramm zu starten, dann sorgt das Betriebssystem dafür, daß dieses Anwendungsprogramm, das wieder eine Folge von Nullen und Einsen ist, in den Hauptspeicher geladen wird. Anschließend werden dem Prozessor nicht mehr die Befehle des Betriebssystems zum Ausführen gegeben, sondern die Befehle des Anwendungsprogramms. Das Betriebssystem unterbricht also die Abarbeitung seiner Befehle zu Gunsten der Befehle des Anwendungsprogrammes. Wenn dieses komplett abgearbeitet ist, dann fährt das Betriebssystem wieder mit der Ausführung seiner eigenen Befehle fort.
Auf diese Weise läßt sich immer nur ein Programm zur Zeit abarbeiten und der Computer kann während dieser Zeit nichts anderes für uns tun. Ein Betriebssystem kann anbieten Prozesse zu verwalten.
Von heutigen Betriebssystemen sind wir gewohnt, daß sie scheinbar mehrere Programme gleichzeitig laufen lassen können und zur selben Zeit auch noch Betriebssystemaufaben wahrnehmen können. Hierzu verwaltet das Betriebssystem mehrere Prozesse und für die verschiedenen Anwendungsprogramme. Das Betriebssystem sorgt dafür, daß in sehr kurzen Zeitabständen zwischen den Prozessen umgeschaltet wird, so daß nacheinander jeder wieder Gelegenheit bekommt, einige seiner Befehle dem Prozessor zur Verarbeitung zukommen zu lassen. Wegen der hohen Geschwindigkeit des Prozessors erscheint es uns so, als liefen mehrere Programme gleichzeitig. Man spricht von Nebenläufigkeit.
Über dieses minimale Szenario bieten heutige Betriebssysteme eine große Anzahl weiterer Funktionalität an. Eine wichtige Funktion ist die Bereitstellung von Bibliotheken, die Anwendungsprogramme benutzen können. Heutige Anwendungsprogramme programmieren nicht alle Funktionalität selbst, sondern nutzen von dem Betriebssystem angebotene Programmteile, z.B. um ein Fenster auf dem Bildschirm darzustellen. Im Anwendungsprogramm stehen dann nicht die einzelnen Befehle, was auf dem Bildschirm darzustellen ist, sondern ein Aufruf an das Betriebssystem, ein Fenster bestimmter Größe und bestimmten Inhalts darzustellen. Der Effekt ist, daß alle Programme, die diese Funktionen des Betriebssystems wahrnehmen, optisch und funktional gleiche vom Betriebssystem verwaltete Fenster haben; aber die Programme sind damit auch an ein bestimmtes Betriebssystem gebunden und können nicht ohne Aufwand auf ein anderes Betriebssystem übertragen werden. Die Anwendungsprogramme werden damit abhängig von dem Betriebssystem, für das sie geschrieben wurden. Auch hierbei führt es immer wieder zu juristischen Fragen: eine Firma, die sowohl ein Betriebssystem als auch Anwendungsprogramme entwickelt, kann sich einen Vorteil vor anderen Firma verschaffen, die auch Anwendungssoftware für dieses Betriebssystem anbieten: sie kann bestimmte interne Funktionalität des Betriebssystems nutzen, die anderen Firma nicht offengelegt wurden.

1.2.2  Beispiele für Betriebssysteme

Obwohl es auf unseren Schreibtischen machnmal so aussieht, als gäbe es nur ein wichtiges Betriebssystem, so ist die Landschaft von Betriebssysteme doch vielfältiger als sie scheinen mag.

1.3  Das Dateisystem

Eine der Hauptaufgaben des Betriebssystems, ist es, das Dateisystem zu verwalten. Dateien sind logische Einheiten von Daten, die auf einem Speichermedium (Festplatte, CD-Rom, Floppy) abgespeichert sind. Dateien haben Namen. Zusätzlich ist das Dateisystem hierarchisch in Ordner geglieder und hat somit eine Baumstruktur. Es gibt einen Wurzelordner, in dem das komplette Dateisystem liegt. Ein Ordner kann als Inhalt weitere Unterordner und Dateien enthalten. Diese hierarchische Baumstruktur kennen so gut wie alle Betriebssysteme. Graphische Benutzeroberflächen stellen diese Baumstruktur in naheliegender Weise dar, wie im nebenstehenden Bildschirmausschnitt aus Linux zu sehen ist.
In Unix werden alle Dateien, die auf unterschiedlichen Medien, wie Festplatten DVDs etc. liegen, in ein Dateisystem integriert (mounting) in Windows werden die verschiedenen Medien durch Laufwerksbuchstaben unterschieden.
Um den genauen Ort einer Datei zu beschreiben, reicht es also nicht aus, den Namen der Datei zu kennen; sondern der Ordner, in dem es liegt, und wiederum dessen Lage bis hin zur Wurzel sind anzugeben.
Figure
Figure 1.1: Baumdarstellung des Dateisystems
Man spricht vom Pfad im Dateibaum, der zu einer Datei führt. Der Pfad gibt an, über welche Ordner von der Wurzel aus gehend, man zu einer Datei gelangt. In der Notation, wie ein Pfad beschrieben wird, unterscheiden sich die wichtigsten Betriebssysteme leicht. Zum Trennen der Ordnerangaben benutzt Unix einen Schrägstrich /, Windows einen rückwärtigen Schrägstrich \ und Apple einen Doppelpunkt.4
Im obigen angegebenen Dateissystem läßt sich eine Datei mit ihrem vollem Pfad in diesen drei Betriebssystemen wie folgt angeben:
Dateien und Ordner haben Namen. Was für Namen erlaubt sind, welche Länge sie haben dürfen und ob Groß- und Kleinschreibung relevant ist, ist abhängig vom Betriebssystem. In Unix ist Groß-/Kleinschreibung relevant, bei Apple und in Windows nicht. DOS kannte nur Namen mit 8 Zeichen.
Eine mit Punkt angehängte Erweiterung des Namens kann angeben, um was für eine Art von Datei es sich handelt, also im Prinzip, wie die Folge von Nullen und Einsen, die gespeichert ist, zu interpretieren ist.5
Hinweis: Windows ist standardmäßig derzeit so eingestellt, daß in der graphischen Darstellung des Dateissystems die Namenserweiterungen nicht angezeigt werden. Dieses ist mitunter gefährlich, denn man kann so eine ausführbare Datei leicht für etwas anderes vielleicht ein Bild ansehen und unbedarft ein trojanisches Pferd oder einen Virus öffnen. Es ist sehr zu empfehlen, diese Einstellung von Windows zu ändern.
Über den Namen und die Ordnerstruktur hinaus, können noch weitere Informationen über Dateien im Betriebssystem abgespeichert werden. So können bestimmte Dateien Benutzern zugeordnet sein und verschiedene Berechtigungen für verschiedene Benutzer haben. Desweiteren speichert das Betriebssystem zu jeder Datei ab, wann sie das letzte Mal geändert wurde und wie groß sie ist.

1.4  Umgang mit der Kommandozeile

Der rudimentärste Umgang mit einem Betriebssystem ist über eine Kommandozeile. Frühere Betriebssysteme kannten nur die Kommandozeile zur Steuerung, so insbesondere die verschiedenen DOS-Systeme. Nur wenige Betriebssystem haben überhaupt keine Kommandozeileneingabe. Die Betriebssystem MacOS bis einschließlich Version 9 kannten keine Kommandozeile6.
Eine Kommandozeile erwartet die Eingabe eines Befehls an das Betriebssystems über die Tastatur. Ein Befehl wird mit dem Drücken der ENTER-Taste aktiviert.
Das Bildschirmfoto in Abbildung zeigt eine Eingabekonsole im Betriebssystem Windows. In Windows ist die Standardeinstellung so, daß der Hintergrund schwarz und die Schrift weiß ist. Diese Farbeinstellung kann geändert werden.
Figure
Figure 1.2: Kommandozeile in Windows
Die Eingabekonsole befindet sich immer in einem bestimmten Ordner, auf den sich alle Befehle beziehen. Wird ein Dateiname ohne explizite komplette Angabe eines Pfades von der Wurzel des Dateibaums gemacht, bezieht sich die Angabe auf den aktuellen Ordner, in dem sich die Konsole befindet. Das aktuelle Verzeichnis wird bei Windows standardmäßig in der Eingabeaufforderung angegeben.

1.4.1  Befehle auf der Kommandozeile

Die gängigsten Befehle, die Unix-artige und DOS-basierte Betriebssysteme kennen, beschäftigen sich mit dem Dateisystem und dem Starten von Programmen.
Es folgt eine kleine tabellarische Übersicht wichtiger Kommandos.
DOSUnixBeschreibung
dirls
zeigt die Dateien im aktuellen Verzeichnis an

cd verzeichnispfadcd verzeichnispfad
wechselt zum Verzeichzeichnis, das durch den verzeichnispfad gekennzeichnet ist. .. steht dabei für den nächsthöheren Ordner.

prognameprogname
startet das Programm progname, sofern dieses auf dem Pfad existiert

touch dateiname
aktualisiert den Zeitstempel der Datei dateiname. Falls eine solche Datei nicht existiert, wird sie mit leerem Inhalt angelegt.

del dateinamerm dateiname
löscht die Datei dateiname komplett aus dem Dateisystem. Es gibt in der Regel keine Sicherheitsnachfrage. Die Datei befindet sich hinterher auch nicht in einem Papierkorb.

ren datei1 datei2mv datei1 datei2
Nenne die Datei datei1 um in datei2. Danach gibt es keine Datei datei1 mehr im Dateisystem.

cp datei1 datei2cp datei1 datei2
Kopiere die Datei datei1 in datei2. Danach gibt es weiterhin die Datei datei1 im Dateisystem.

mkdir ordnermkdir ordner
Erzeuge einen neuen Ordner.

chmodmods filechmod mods file
Ändert die Zugriffsberechtigung der Datei oder des Ordners file nach den in mods angegebene Schema. Benutzer werden hier spezifiziert nach: u für den Besitzer der Datei, g für die Gruppe, der die Datei zugeordnet ist, o für alle weiteren Benutzer und a für alle Benutzer. Es gibt Berechtigungen wiew zum Schreiben, r zum Lesen und x zum Ausführen. Ein Plus- oder Minuszeichen vergibt Rechte oder nimmt sie wieder. z.B. chmod a+r myFile erlaubt allen Benutzer die Datei myFile zu lesen.

Wie man sieht, liegen DOS und Unix in diesem Fall nicht sehr weit auseinander.
Die Befehle kenne zusätzlich noch weitere Optionen, diese werden dem Befehl durch Leerzeichen getrennt nachgestellt. Optionen sind in der Regel in Unix durch ein vorangestelltes Minuszeichen und in Windows durch einen Schrägstrich gekennzeichnet. So kennt der Befehl ls z.B. die Option -l bzw. /l, um eine detaillierte Darstellung der Dateiinformation zu geben, oder die Option -a um auch versteckte Dateien anzuzeigen.
Es gibt auf der Kommandozeile auch Möglichkeiten, mehr als eine Datei zu beschreiben. Hierzu bedient man sich des Zeichens *, das 0 bis n beliebige Zeichen stehen kann.
Die Kommandoeingabe bietet eine Hilfe an. Hierzu kann man den Befehl help benutzen.
Beispiel:
Ein paar kleine Beispiele für Befehle auf der Kommandozeile:

1.4.2  Skripte

Wie man sehen kann, indem man das Kommando help in der Kommandozeile eingibt, kennt die Kommandozeile schon eine Vielzahl von Befehlen. Damit stellt die Kommandozeile schon eine Art Programmiersprache dar. Ein Kommandozeilenprogramm besteht aus einer Folge von Befehlen, die die Kommandozeile versteht. Solche Programme können geschrieben werden. Hierzu schreibt man mit einem einfachen Texteditor eine Datei mit der Endung .sh in Unix oder .bat in Windows. In dieser Datei können nacheinander die Befehle an die Eingabekonsole geschrieben werden. Die Datei wird abgespeichert. Anschließend gibt man ihr mit dem Befehl chmod a+x die Berechtigung zum Ausführen. Nun läßt sich die Textdatei als Programm starten.
Beispiel:
Als Beispiel schreiben wir ein kleines zweizeiliges Skript, das erst einen neuen Ordner erzeugt, und dann die Dateien mit der Endung .class in diesen Ordner verschiebt.
mkdir classes
mv *.class classes

Diese Skript speichern wir unter den Namen mvClasses.sh ab. Schließlich setzen wir die Berechtigung zum Ausführen und führen das Programm aus.
sep@swe10:~/fh/internal/beispiele/jugs> chmod a+x mvClasses.sh
sep@swe10:~/fh/internal/beispiele/jugs> mvClasses.sh
sep@swe10:~/fh/internal/beispiele/jugs>

1.4.3  Umgebungsvariablen

Ein Betriebssystem hat Variablen, in denen es globale Werte abspeichert, wie z.B. den Rechnernamen oder den Benutzernamen. Die Gesamtheit dieser Werte nennt man Umgebung und die einzelnen Variablen Umgebungsvariablen. Über die Kommandozeile können Umgebungsvariablen abgefragt werden. Wenn man z.B. in Windows den Befehl set eingibt, so folgt eine Auflistung aller bekannten Umgebungsvariablen und ihrer Werte.

1.5  Programm und Maschine

Bevor wir im nächsten Kapitel anfangen eigene Programme zu schreiben, sollten wir uns zunächst eimnal darüber klar werden, was ein Programm überhaupt ist, und was eine Programmiersprache ausmacht. Ein Programm, das wir im Betriebssystem starten, sei es durch Aufruf in der Kommandozeile, sei es durch einen Doppelklick auf der graphischen Oberfläche, ist eine Folge von Nullen und Einsen. Wir sprechen von einer Binärdatei im Gegensatz zu Textdateien. In Windows hat ein Programm zumeist die Erweiterung .exe. Die Nullen und Einsen eines Programms kodieren direkt Befehle des Prozessors. Wenn das Programm gestartet wird, dann werden diese Befehle direkt an den Prozessor gegeben, der diese ausführt.

1.5.1  Programmiersprachen

Ein Programmierer, der ein Programm schreibt, erzeugt aber nicht diese ausführbare Binärdatei. So gut wie nie kennt der Programmierer die Befehle des Prozessors oder könnte die Binärdatei selbst erzeugen. Der Programmierer schreibt ein Programm in einer Programmiersprache.
Programme einer Programmiersprache sind Texte, die mit einem einfachen Texteditor geschrieben werden können. Die Definition der Programmiersprache legt fest, was es für Befehle und Strukturierungsmöglichkeiten gibt. Hierzu hat eine Programmiersprache eine Grammatik ganz analog zu natürlichen Sprachen. In dieser Hinsicht ist eine Programmiersprache zunächst vollkommen unabhängig von einem konkreten Computer eine formal definierte Sprache. Damit ein Programm, das in einer Programmiersprache geschrieben wurde, von einem Computer ausgeführt werden kann, muß es entweder in eine Folge von Prozessorbefehlen übersetzt werden, oder aber in irgendeiner Weise interpretiert werden.

1.5.2  Kompilierung

Zum Übersetzen einer Textdatei, die das Programm darstellt, das ein Programmierer geschrieben hat, in eine durch den Prozessor ausführbare Binärdatei benötigt man ein Werkzeug, den sogenannten Compiler. Ein Compiler bekommt als Eingabe eine Textdatei, die ein in einer Programmiersprache geschriebenes Programm enthält. Er prüft zunächst, ob das Programm nach den Regeln der Programmiersprache korrekt geschrieben wurde. Wenn die Prüfung keinen Fehler gefunden hat, erzeugt der Compiler für dieses Programm eine ausführbare Binärdatei. Ein Compiler ist ein Übersetzer von einer Programmiersprache in die Maschinensprache eines Computers. Der Compiler ist auch ein Programm, das von der Kommandozeile aus gestartet werden kann.
Beispiel:
C ist eine Programmiersprache mit einem Compiler. Folgendes kleine C-Programm gibt den Text hallo welt auf dem Bildschirm aus:
int main(){
    printf("hallo welt\n");
    return 0;
}

Dieses Programm läßt sich mit einen normalen Texteditor schreiben. Dann kann es mit dem C-compiler gcc übersetzt werden, um dann ausgeführt zu werden:
sep@swe10:~/fh/dv2> ls hallo*
hallo.c
sep@swe10:~/fh/dv2> gcc -o hallo.exe hallo.c
sep@swe10:~/fh/dv2> ls hallo*
hallo.c  hallo.exe
sep@swe10:~/fh/dv2> ./hallo.exe
hallo welt
sep@swe10:~/fh/dv2>

1.5.3  Interpreter

Statt ein Programm in eine Binärdatei zu übersetzen, gibt es noch eine zweite Möglichkeit, wie ein Programm zu Ausführung gelangt. Der Programmtext wird nicht in eine ausführbare Datei übersetzt sondern durch einen Interpreter Stück für Stück anhand des Quelltextes ausgeführt. Hierzu muß stets der Interpreter zur Verfügung stehen, um das Programmm auszuführen. Interpretierte Programme sind langsamer in der Ausführung als übersetzte Programme. Eine populäre interpretierte Sprache ist Lisp.

1.5.4  Java

Java hat eine dritte Form der Ausführung, indem eine abstrakte Maschine mit byte code benutzt wird. Dieses ist quasi eine Mischform aus den obigen zwei Ausführungsmodellen. Der Quelltext wird in Befehle übersetzt nicht für einen konkreten Computer, sondern für eine abstrakte Maschine. Für diese abstrakte Maschine steht dann ein Interpreter zur Verfügung. Der Vorteil ist, daß durch die zusätzliche Abstraktionsebene der Übersetzer unabhängig von einer konkreten Maschine Code erzeugen kann und das Programm auf auf allen Systemen laufen kann, für die es einen Interpreter der abstrakten Maschine gibt, aber trotzdem schneller ist als ein rein interpretiertes Programm.
Das bedeutet insbesondere, daß man zwei Programme braucht um Javaprogramm zu übersetzen und laufen zu lassen. Es wird ein Compiler benötigt, der den Code für die abstrakte Maschine erzeugt, und es wird ein Intepreter benötigt, der die abstrakte Maschine auf den konkreten Rechner realisiert. Diese beiden Programme heißen javac und java.

1.6  Disziplinen der Programmierung

Mit dem Begriff Programmierung wird zunächst die eigentliche Codierung eines Programms assoziiert. Eine genauerer Blick offenbart jedoch, daß dieses nur ein kleiner Teil von vielen recht unterschiedlichen Schritten ist, der zur Erstellung von Software notwendig ist:

Chapter 2
Grundkonzepte der Programmierung

Mit der uns umgebenen Technik eines heutigen Computer sind wir jetzt soweit vertraut, daß wir wissen, was wir tun, wenn wir ein Programm schreiben. Wir wollen am Beispiel von Java nun einige Grundkonzpte der Programmierung kennenlernen und ausprobieren.
In der Programmierung kann man generell unterscheiden zwischen den passiven Daten und den Programmen, die diese Daten manipulieren. Daten können Zahlen oder Texte, aber auch Listen, Tabellen, ganze Dokumente, Bilder etc. sein. Programme manipulieren diese Daten, verändern, löschen oder legen sie neu an.

2.1  Module und Unterprogamme

In kaum einer Programmiersprache stehen alle Befehle des Programms in einer Folge untereinander. Es gibt zwei Hauptstrukturierungsmöglichkeiten:
Ein Javaprogramm besteht aus einer Menge von Klassen. Jede Klasse wird in einer eigenen Datei geschrieben. Der Dateiname besteht aus dem Namen der Klasse und hat die Endung .java. Hierbei ist Groß- und Kleinschreibung relevant.
Beispiel:
Die einfachste Klasse die man sich denken kann enthält keine Unterprogramme. Sie ist leer. Sie stellt ein leeres Modul dar. Sie besteht nur aus dem Wort class gefolgt vom frei wählbaren Namen der Klasse und einem Paar geschweifter Klammern:
Minimal
class Minimal { }

2.2  Die Hauptmethode

2.2.1  Das erste Java Programm

Ein Programm besteht aus einer Menge von Unterprogrammen, die in unteschiedlichen Modulen stehen können. Eines dieser Unterprogramme muß als besonderes Unterprogramm ausgezeichnet sein, nämlich als das Programm, mit dem bei der Ausführung zu beginnen ist. In Java heißt dieses Unterprogramm main8. Wenn man den Javainterpreter sagt, er solle ein Programm ausführen, dann gibt man ihn einen Klassennamen an. Der Javainterpreter erwartet dann, daß es in dieser Klasse eine Methode mit dem Namen main gibt. Wenn dieses der Fall ist, so führt der Javainterpreter diese Methode aus, andernfalls gibt es eine Fehlermeldung.
Beispiel:
Unser erstes Programm mit einer main-Methode. Dieses Programm gibt auf der Kommandozeile den Text "hallo welt" aus:
Hallo
class Hallo {
  public static void main (String [] args){
    System.out.println("hallo welt");
  }
}

Aufgabe 0   Schreiben Sie das obige Programm mit einen Texteditor ihrer Wahl. Speichern Sie es als Hallo.java ab. Übersetzen Sie es mit dem Java-Übersetzer javac. Es entsteht eine Datei hallo.class. Führen Sie das Programm mit dem Javainterpreter java aus.
Im obigen Beispiel sehen wir schon fast alles, was zur Syntax eines Javaprogramms gehört:
Die Bedeutung der Schlüsselwörter, die vor unserer Methode main stehen (public static void) werden wir erst an späterer Stelle erklären. Man merke sich, daß die Startmethode stets mit diesen Schlüsselwörtern zu beginnen hat. Die Startmethode hat einen Parameter (String [] args). Auch diesen hinterfragen wir noch nicht, merken uns aber, daß er für eine Startmethode existieren muß.
Wir haben in unserem Programm bestimmte Einrückungen vorgenommen. Diese sind für Java technisch nicht notwendig, sondern sollen uns die Lesbarkeit des Programms erleichtern.
Aufgabe 1   Übersetzen Sie das Programm Minimal aus dem letzem Abschnitt und versuchen Sie dieses Programm laufen zu lassen. Was für eine Fehlermeldung bekommen Sie?

2.2.2  Das zweite Java Programm

Das Programmodul Hallo enthielt nur eine Methode und diese enthielt nur einen Befehl, nämlich System.out.println("hallo welt").
Ein Unterprogramm kann mehrere Befehle enthalten. Diese Befehle werden dann nacheinander ausgeführt. Jeder Befehl endet mit einem Semikolon.
Beispiel:
Das folgende Programm enthält mehrere Befehle in der Hauptmethode. Zweimal wird ein Text ausgegeben und anschließend das Ergebnis einer arithmetischen Berechnung.
Zwei
class Zwei {

  public static void main (String [] args){
    System.out.println("hallo welt");
    System.out.println("3*3 ist");
    System.out.println(3*3);
  }
}

Wie wir sehen können wir auch arithmetische Ausdrücke schreiben, deren Wert dann bei der Ausführung von Java berechnet wird.

2.3  Methoden

Bisher haben wir nur Klassen mit genau einer Methode, der Hauptmethode, geschrieben. Betrachten Sie das folgende Programm:
Drei
class Drei{
  public static void main (String [] args){
    System.out.println("*******");
    System.out.println("3*3 ist");
    System.out.println(3*3);
    System.out.println("*******");
  }
}

es enthält drei verschiedene Befehle, von denen einer zweimal verwendet wird, nämlich der Befehl:
System.out.println("*******");
Wann immer eine bestimmte Befehlsfolge mehrfach in einem Programm auftaucht, ist diese ein guter Kanditat in ein eigenes Unterprogramm ausgelagert zu werden. Dann kann jeweils die fragliche Befehlsfolge durch einen Aufruf an das neue Unterprogramm ersetzt werden.

2.3.1  Methodendeklaration

Wir können für bestimmten Code eine eigene Methode definieren. Die Methodendefinition unterscheidet sich dann in ihrer Art nicht von der Definition der Startmethode: wir können einen Namen für die Methode frei wählen. Vor dem Methodennamen stehen zusätzliche Informationen zur Methode, nach dem Methodennamen zunächst eine in runden Klammern eingeschlossene Liste von Parametern und schließlich in geschweiften Klammern eingeschlossen die Befehle der Methode.
Beispiel:
In der folgenden Klasse schreiben wir zur Startmethode noch eine zusätzliche Methode mit Namen zierleiste.
DreiPlus
class DreiPlus{
  public static void main (String [] args){
    System.out.println("*******");
    System.out.println("3*3 ist");
    System.out.println(3*3);
    System.out.println("*******");
  }

  public static void zierleiste(){
    System.out.println("*******");
  }
}

2.3.2  Methodenaufruf

Methoden, die wir definiert haben, können jetzt an beliebiger Stelle aufgerufen werden. Ein Methodenaufruf besteht aus dem Methodennamen gefolgt von in runden Klammern eingeschlossenen konkreten Parametern.
Beispiel:
Da wir zum Drucken der Zierleiste eine eigene Methode geschrieben haben, können wir diese in der Startmethode aufrufen, anstatt ihren Code direkt zu schreiben.
DreiPlusPlus
class DreiPlusPlus{
  public static void main (String [] args){
    zierleiste();
    System.out.println("3*3 ist");
    System.out.println(3*3);
    zierleiste();
  }

  public static void zierleiste(){
    System.out.println("*******");
  }
}

Es ist hierbei egal, in welcher Reihenfolge die Methoden einer Klasse auftreten. Eine Methode kann aufgerufen werden, auch wenn sie erst an späterer Stelle im Programm definiert wird.

2.4  Unsere ersten Typen

Bisher haben wir schon zwei verschiedene Arten von Daten kennengelernt. Man spricht dabei auch von Typen. Der eine Typ stellte beliebige Zeichenketten dar. Dieser Typ heißt String. In einem der Beispiel haben wir zusätzlich gesehen, daß wir mit Zahlen rechnen können. Der Typ der ganzen Zahlen wird in Java10 als int bezeichnet.

2.5  Methoden mit Parametern

Bisher haben wir nur Methoden denen ein leeres Klammernpaar folgte, geschrieben. Solche Methoden nennt man parameterlose Methoden. Wir können aber auch einer Methode für ihre Ausführung Daten übergeben, mit denen die Methode arbeiten soll. Hierzu muß in der Definition einer Methode deklariert sein, was für Typen von Daten die Methode erwartet. Hierzu schreibt man in der Methodendefinition in die runden Klammern für die Parameter den Namen des Typs der erwarteten Daten. Diesem Typnamen folgt ein frei wählbarer Name für den Parameter, damit wir uns mit Hilfe dieses Parameternamens in den Befehlen der Methode auf den Parameter beziehen können. Beim Aufruf der Methode sind für die Parameter entsprechende Daten zu übergeben.
Beispiel:
Wir schreiben die erste eigene Methode mit einem Parameter. Die Methode druckeDoppelt erwartet in ihrem Aufruf eine Zeichenkette. Die Methode gibt die übergebene Zeichenkette dann zweimal auf dem Bildschirm aus.
Doppeldruck
class Doppeldruck {

  public static void main(){
    druckeDoppelt("hallo");
    druckeDoppelt("Ilja");
  }

  public static void druckeDoppelt(String text){
    System.out.println(text);
    System.out.println(text);
  }
 
}

Aufgabe 2   Testen Sie, was passiert, wenn Sie im obigen Programm die Methode druckeDoppelt ohne konkreten Wert für den Parameter aufrufen.

2.5.1  rekursive Methoden

Wir haben gelernt, daß Methopden überall aufgerufen werden kann. Eine Methode kann sogar in ihrem eigenen Rumpf aufgerufen werden.
Beispiel:
In der folgenden Klasse ruft die Methode ganzOft sich selbst wieder auf. Der Effekt ist, daß dadurch endlos hallo auf dem Bildschirm ausgegeben wird.
GanzOft
class GanzOft{

  public static void main(String [] args){
    ganzOft("hallo");
  }

  public static void ganzOft(String x){
    System.out.println(x);
    ganzOft(x);
  }
}

Methoden, die sich selbst wieder aufrufen, nennt man rekursiv.

2.6  Methoden mit Rückgabewert

Unsere Methoden haben bisher nur einen Befehl benutzt, nämlich etwas auf dem Bildschrim auszugeben. In einem Programm werden in der Regel Ergebnisse berechnet. Hierzu kann man Unterprogramme schreiben, deren Ausführung ein Ergebnis errechnen. Damit bekommt eine Methode nicht nur über die Parameter Daten als Eingabe, sondern berechnet ein Ergebnis und gibt dieses Ergebnis an die aufrufende Stelle zurück. Hierzu ist statt des Schlüsselwortes void in der Methodendefinition der Typname für die Art der Daten, die als Ergebnis berechnet werden, anzugeben. In einer Methode, die eine ganze Zahl als Ergebnis hat, ist statt void also der Typname int zu schreiben.
Zusätzlich ist in einer Methode, die ein Ergebnis berechnet auch noch ein return-Befehl zu schreiben. Der return-Befehl sorggt dafür, daß die Berechnung beendet wird und der Wert, der nach dem Wort return folgt als Ergebnis zurückzugeben ist.
Eine Methode mit Parameter und einem Rückgabewert entsprich einer mathematischen Funktion. Die Mathematikunterricht oft benutzte Funktion: f(x)=x2 ist Javatechnisch eine Methode mit einem Zahlenparameter und einer Zahl als Ergebnis.
Beispiel:
In der folgenden Klasse schreiben wir eine Methode, die für ihren Parameter die Quadratzahl als Ergebnis liefert.
Quadrat
class Quadrat {

  public static void main(){
    System.out.println(quadrat(2));
    System.out.println(quadrat(3));
    System.out.println(quadrat(4));
    System.out.println(quadrat(5));
  }

  public static int quadrat(int x){
    return x*x;
  }

}

Aufgabe 3   Schreiben Sie eine zusätzliche Methode in obiger Klasse. Die Methode soll zwei Zahlen x und y als Parameter haben und als Ergebnis 2*x+4*y berechnen.

2.7  Wahrheitswerte

Ein in der Informatik häufig gebrauchte Unterscheidung ist, ob etwas wahr oder falsch ist, also eine Unterscheidung zwischen genau zwei Werten.11 Hierzu bedient man sich der Wahrheitswerte aus der formalen Logik. Java bietet einen primitiven Typ an, der genau zwei Werte annehmen kann, den Typ: boolean. Die Bezeichnung ist nach dem englischen Mathematiker und Logiker George Bool (1815-1869) gewählt worden.
Entsprechend der zwei möglichen Werte für diesen Typ stellt Java auch zwei Literale zur Verfügung: true und false.
Bool'sche Daten lassen sich ebenso wie numerische Daten benutzen. Methoden können diesen Typ verwenden.
Testbool
class Testbool{
  public static void main(String [] args){
    System.out.println(true);
  }

  public static boolean traceBoolean(boolean b){
    System.out.println(b);
    return b;
  }
}

2.8  Operatoren

Wir haben jetzt gesehen, was Java uns für Typen zur Darstellung von Zahlen zur Verfügung stellt. Jetzt wollen wir mit diesen Zahlen nach Möglichkeit auch noch rechnen können. Wir haben in den vorhergehenden Abschnitten stillschweigend schon ein paar der von Java zur Verfügung gestellten wie *, -, / etc. benutzt. Prinzipell gibt es in der Informatik für Operatoren drei mögliche Schreibweisen:

2.8.1  Die Grundrechenarten

Java stellt für Zahlen die vier Grundrechenarten zur Verfügung.
Bei der Infixnotation gelten für die vier Grundrechenarten die üblichen Regeln der Bindung, nämlich Punktrechnung vor Strichrechnung. Möchte man diese Regel durchbrechen, so sind Unterausdrücke in Klammern zu setzen. Folgende kleine Klasse demonstriert den Unterschied:
PunktVorStrich
class PunktVorStrich{
  public static void main(String [] args){
    System.out.println(2 + 20 * 2);
    System.out.println((2 + 20) * 2);
  }
}

Wir können nun also Methoden schreiben, die Rechnungen vornehmen. In der folgenden Klasse definieren wir z.B. eine Methode, zum Berechnen der Quadratzahl der Eingabe:
Square
class Square{
  static int square(int i){
    return i*i;
  }
}

2.8.2  Vergleichsoperatoren

Obige Operatoren rechnen jeweils auf zwei Zahlen und ergeben wieder eine Zahl als Ergebnis. Vergleichsoperatoren vergleichen zwei Zahlen und geben einen bool'schen Wert, der angibt, ob der Vergleich wahr oder falsch ist. Java stellt die folgenden Vergleichsoperatoren zur Verfügung: <, <=, >, >=, !=, ==. Für die Gleichheit ist in Java das doppelte Gleichheitszeichen == zu schreiben, denn das einfache Gleichheitszeichen ist bereits für den Zuweisungsbefehl vergeben. Die Ungleichheit wird mit!= bezeichnet.
Folgende Tests demonstrieren die Benutzung der Vergleichsoperatoren.
Vergleich
class Vergleich{

  public static void main(String[] args){
    System.out.println(1+1 < 42);
    System.out.println(1+1 <= 42);
    System.out.println(1+1 >  42);
    System.out.println(1+1 >= 42);
    System.out.println(1+1 == 42);
    System.out.println(1+1 != 42);
  }
}

2.8.3  Bool'sche Operatoren

In der bool'schen Logik gibt es eine ganze Reihe von binären Operatoren für logische Ausdrücke. Für zwei davon stellt Java auch Operatoren bereit: && für das logische und (Ù) und|| für das logische Oder (Ú).
Zusätzlich kennt Java noch den unären Operator der logischen Negation Ø. Er wird in Java mit ! bezeichnet.
Wie man im folgenden Test sehen kann, gibt es auch unter den bool'schen Operatoren eine Bindungspräzedenz, ähnlich wie bei der Regel Punktrechnung vor Strichrechnung. Der Operator && bindet stärker als der Operator ||:
TestboolOperator
class TestboolOperator{
  public static void main(String [] args){
    System.out.println(true && false);
    System.out.println(true || false);
    System.out.println(!true || false);
    System.out.println(true || true && false);
  }
}

In der formalen Logik kennt man noch weitere Operatoren, z.B. die Implikation ®. Diese Operatoren lassen sich aber durch die in Java zur Verfügung stehenden Operatoren ausdrücken. A® B entspricht ØAÚB. Wir können somit eine Methode schreiben, die die logische Implikation testet.
TestboolOperator2
class TestboolOperator2{
  static boolean implication(boolean a, boolean b){
    return !a || b;
  }

  public static void main(String [] args){
    System.out.println(implication(true, false));
  }
}

2.8.4  Der Operator + auf String

Wir haben den Operator + kennengelernt als Additionsoperator für Zahlen. Er kann aber auch benutzt werden, um zwei Strings aneinanderzuhängen. Dann sind beide Operanden vom Typ String. Man kann das Pluszeichen aber auch so verwenden, daß ein Operand ein String und der andere eine Zahl. Dann ist Java so konzipiert, daß es die Zahl erst in einen entsprechenden String umwandelt.
Beispiel:
Die folgende Klasse benutzt den Operator + auf unterschiedlichen Operanden.
TestboolOperator2
class OperatorPlus {

  public static void main(String [] args){
    System.out.println("hallo"+" welt");
    System.out.println("1"+"1");
    System.out.println(1+1);
    System.out.println("1"+1);
    System.out.println(1+"1");
  }
}

Puristen kritisieren gerne diese mehrfache Bedeutung des Pluszeichens in Java, insbesondere weil "1"+"1" das Ergebis "11" hat und 1+1 als Ergebnis 2.

2.9  Felder

Wir kennen jetzt Methoden als die eigentlichen Programmteile. Methoden können Daten in Form von Parametern als Eingabe bekommen und Daten als Ergebnis berechnen. In Programmiersprachen gibt es ein zusätzliches Konzept, um Daten zwischenzuspeichern. In Java heißt dieses Konzept Feld, man spricht in anderen Sprachen und auch in Java oft von Variablen. Ein Feld ist ein Platz, in dem Daten abgelegt werden können, um sie bei einem späteren Befehl wieder benutzen zu können. Die Daten, die in einem Feld stehen können verändert werden. Hierzu gibt es den Zuweisungsbefehl. Ein Feld muß bevor es benutzt werden kann, deklariert werden. Damit wird der Javamaschine gesagt, daß ein Speicherplatz benötigt wird, in dem bestimmte Daten abgelegt werden sollen. Eine Felddeklaration besteht aus einem Typnamen gefolgt von einem frei wählbaren Feldnamen. Per Konvention beginnt der Feldname mit einem Kleinbuchstaben. Felder können an beliebiger Stelle deklariert werden, z.B. zwischen zwei Befehlen. In einem Feld werden Daten durch den Zuweisungsbefehl geschrieben, der Zuweisungsbefehl besteht aus einem Gleichheitszeiche. Links von dem Gleichheitszeichen steht ein Feldame, rechts davon stehen die Daten, die in das Feld geschrieben werden sollen.
Beispiel:
In der Hauptmethode der folgenden Klassen werden nacheinander 4 Zahlen in ein Feld geschrieben, die dann jeweils benutzt werden, um den Wert des Feldes auf dem Bildschirm auszugeben.
FirstField
class FirstField {
  public static void main(){
    int i;
    i=1;
    System.out.println(i);
    i=2;
    i=3;
    System.out.println(i);
    i=4;
    System.out.println(i);
  }
}

In einem Feld können insbesondere auch Ergebnisse von Methoden abgespeichert werden:

2.10  Zusammengesetzte Befehle

Streng genommen kennen wir bisher nur einen Befehl, den Zuweisungsbefehl, der einem Feld einen neuen Wert zuweist.12 In diesem Abschnitt lernen wir weitere Befehle kennen. Diese Befehle sind in dem Sinne zusammengesetzt, daß sie andere Befehle als Unterbefehle haben.

2.10.1  Bedingungsabfrage mit: if

Ein häufig benötigtes Konstrukt ist, daß ein Programm abhängig von einer bool'schen Bedingung, sich verschieden verhält. Hierzu stellt Java die if-Bedingung zur Verfügung. Dem Schlüsselwort if folgt in Klammern eine bool'sche Bedingung, anschließend kommen in geschweiften Klammern die Befehle, die auszuführen sind, wenn die Bedingung wahr ist. Anschließend kann optional das Schlüsselwort else folgen mit den Befehlen, die andernfalls auszuführen sind.
FirstIf
class FirstIf {

  static void firstIf(boolean bedingung){
    if (bedingung) {
      System.out.println("Bedingung ist wahr");
    } else {
      System.out.println("Bedingung ist falsch");
    }
  }
 
  public static void main(String [] args){
     firstIf(true || false);
  }

}

Das if-Konstrukt erlaubt es uns also Fallunterscheidungen zu treffen. Wenn in den Alternativen nur ein Befehl steht, so können die geschweiften Klammern auch fortgelassen werden. Unser Beispiel läßt sich also auch schreiben als:
FirstIf2
class FirstIf2 {

  static void firstIf(boolean bedingung){
    if (bedingung) System.out.println("Bedingung ist wahr");
    else System.out.println("Bedingung ist falsch");
  }
 
  public static void main(String [] args){
     firstIf(true || false);
  }

}

Eine Folge von mehreren if-Konstrukten lassen sich auch direkt hintereinanderschreiben, so daß eine Kette von if und else-Klauseln entsteht.
ElseIf
class ElseIf {

  static String lessOrEq(int i,int j){
    if (i<10)  return "i kleiner zehn";
    else if (i>10)  return "i größer zehn";
    else if (j>10)  return "j größer zehn";
    else if (j<10)  return "j kleiner zehn";
    else return "j=i=10";
  }
 
  public static void main(String [] args){
     System.out.println(lessOrEq(10,9));
  }

}

Wenn zuviele if-Bedingungen in einem Programm einander folgen und ineinander verschachtelt sind, dann wird das Programm schnell unübersichtlich. Man spricht auch von Spaghetti-code. In der Regel empfiehlt es sich, in solchen Fällen noch einmal über das Design nachzudenken, ob die abgefragten Bedingungen sich nicht durch verschiedene Klassen mit eigenen Methoden darstellen lassen.
Mit der Möglichkeit in dem Programm abhängig von einer Bedingung unterschiedlich weiterzurechnen, haben wir theoretisch die Möglichkeit, alle durch ein Computerprogramm berechenbaren mathematischen Funktionen zu programmieren. So können wir z.B. eine Methode schreiben, die für eine Zahl i die Summe von 1 bis n berechnet.
Summe
class Summe{
  static int summe(int i){
    if (i==1)  {
      return 1;
    }else {
      return summe(i-1) + i;
    }
  }
}

Wir können diese Programm von Hand ausführen, indem wir den Methodenaufruf für summe für einen konkreten Parameter i durch die für diesen Wert zutreffende Alternative der Bedingungsabfrage ersetzen. Wir kennzeichnen einen solchen Ersetzungsschritt durch einen Pfeil ®.
summe(4)
®summe(4-1)+4
®summe(3)+4
®summe(3-1)+3+4
®summe(2)+3+4
®summe(2-1)+2+3+4
®summe(1)+2+3+4
®1+2+3+4
®3+3+4
®6+4
®10
Wie man sieht wird für i=4 die Methode summe genau viermal wieder aufgerufen, bis schließlich die Alternative mit dem konstanten Rückgabewert 1 zutrifft. Unser Trick war, im Methodenrumpf die Methode, die wir gerade definieren, bereits zu benutzen. Diesen Trick nennt man in der Informatik Rekursion. Mit diesem Trick ist es uns möglich, ein Programm zu schreiben, bei dessen Ausführung ein bestimmter Teil des Programms mehrfach durchlaufen wird.
Das wiederholte Durchlaufen von einem Programmteil ist das A und O der Programmierung. Daher stellen Programmiersprachen in der Regel Konstrukte zur Verfügung, mit denen man dieses direkt ausdrücken kann. Die Rekursion ist lediglich ein feiner Trick, dieses zu bewerkstelligen. In den folgenden Abschnitten lernen wir die zusammengesetzten Befehle von Java kennen, die es erlauben auszudrücken, daß ein Programmteil mehrfach zu durchlaufen ist.
Aufgabe 4   Schreiben Sie eine Methode, die für eine ganze Zahl die Fakultät dieser Zahl berechnet. Testen Sie die Methode zunächst mit kleinen Zahlen, anschließend mit großen Zahlen. Was stellen Sie fest.

2.10.2  Iteration

Die im letzten Abschnitt kennengelernte Programmierung der Programmwiederholung der Rekursion kommt ohne zusätzliche zusammengesetzte Befehle von Java aus. Da Rekursionen von der virtuellen Maschine Javas nur bis zu einen gewissen Maße unterstützt werden, bietet Java spezielle Befehle an, die es erlauben, einen Programmteil kontrolliert mehrfach zu durchlaufen. Die entsprechenden zusammengesetzten Befehle heißen Iterationsbefehle. Java kennt drei unterschiedliche Iterationsbefehle.

Schleifen mit: while

Ziel der Iterationsbefehle ist es, einen bestimmten Programmteil mehrfach zu durchlaufen. Hierzu ist es notwendig, eine Bedingung anzugeben, für wie lange eine Schleife zu durchlaufen ist. while-Schleifen in Java haben somit genau zwei Teile:
Java unterscheidet zwei Arten von while-Schleifen: Schleifen für die vor dem Durchlaufen der Befehle des Rumpfes die Bedingung geprüft wird, und Schleifen, für die nach Durchlaufen es Rumpfes die Bedingung geprüft wird.
Vorgeprüfte Schleifen  
Die vorgeprüfte Schleifen haben folgendes Schema in Java:
while (pred){body}

pred ist hierbei ein Ausdruck, der zu einem bool'schen Wert auswertet. body ist eine Folge von Befehlen. Java arbeitet die vorgeprüfte Schleife ab, indem erst die Bedingung pred ausgewertet wird. Ist das ergebnis true dann wird der Rumpf (body) der Schleife durchlaufen. Anschließend wird wieder die Bedingung geprüft. Dieses wiederholt sich so lange, bis die Bedingung zu false auswertet.
Ein simples Beispiel einer vorgeprüften Schleife ist folgendes Programm, das die Zahlen von 0 bis 9 auf dem Bildschirm ausgibt:
WhileTest
class WhileTest {
  public static void main(String [] args){
    int i = 0;
    while (i < 10){
      i = i+1;
      System.out.println(i);    
    }
  }
}

Mit diesen Mitteln können wir jetzt versuchen, die im letzten Abschnitt rekursiv geschriebene Methode summe iterativ zu schreiben:
Summe2
class Summe2 {
  public static int summe(int n){

    int erg = 0 ;              // Feld für Ergebnis
    int j   = n ;              // Feld zur Schleifenkontrolle

    while (j>0){               // j läuft von n bis 1     
      erg = erg + j;           // akkumuliere das Ergebnis
      j = j-1;                 // verringere Laufzähler
    }

    return erg;
  }
}

Wie man an beiden Beispielen oben sieht, gibt es oft ein Feld, das zur Steuerung der Schleife benutzt wird. Dieses Feld verändert innerhalb des Schleifenrumpfes seinen Wert. Abhängig von diesem Wert wird die Schleifenbedingung beim nächsten Bedingungstest wieder wahr oder falsch.
Schleifen haben die unangenehme Eigenschaft, daß sie eventuell nie verlassen werden. Eine solche Schleife läßt sich minimal wie folgt schreiben:
Bottom
class Bottom {
   static public void bottom(){
     while (true){}
   }
}

Ein Aufruf der Methode bottom startet eine nicht endende Berechnung.
Häufige Programmierfehler sind inkorrekte Schleifenbedingungen, oder falsch kontrollierte Schleifenvariablen. Das Programm terminiert dann mitunter nicht. Solche Fehler sind in komplexen Programmen oft schwer zu finden.
Nachgeprüfte Schleifen  
In der zweiten Variante der while-Schleife steht die Schleifenbedingung syntaktisch nach dem Schleifenrumpf:
do {body} while (pred)

Bei der Abarbeitung einer solchen Schleife wird entsprechend der Notation, die Bedingung erst nach der Ausführung des Schleifenrumpfes geprüft. Am Ende wird also geprüft, ob die Schleife ein weiteres Mal zu durchlaufen ist. Das impliziert insbesondere, daß der Rumpf mindestens einmal durchlaufen wird.
Die erste Schleife, die wir für die vorgeprüfte Schleife geschrieben haben, hat folgende die nachgeprüfte Variante:
DoTest
class DoTest {
  public static void main(String [] args){
    int i = 0;
    do {
      System.out.println(i);    
      i = i+1;
    } while (i < 10);
  }
}

Man kann sich leicht davon vergewissern, daß die nachgeprüfte Schleife mindestens einmal durchlaufen13 wird:
VorUndNach
class VorUndNach {

  public static void main(String [] args){

      while (falsch()) 
         {System.out.println("vorgeprüfte Schleife");};

      do {System.out.println("nachgeprüfte Schleife");} 
      while (false);
  }

  public static boolean falsch(){return false;}
}

Schleifen mit: for

Das syntaktisch aufwendigste Schleifenkonstrukt in Java ist die for-Schleife.
Wer sich die obigen Schleifen anschaut, sieht, daß sie an drei verschiedenen Stellen im Programmtext Code haben, der kontrolliert, wie oft die Schleife zu durchlaufen ist. Oft legen wir ein spezielles Feld an, dessen Wert die Schleife kontrollieren soll. Dann gibt es im Schleifenrumpf einen Zuweisungsbefehl, der den Wert dieses Feldes verändert. Schließlich wird der Wert dieses Feldes in der Schleifenbedingung abgefragt.
Die Idee der for-Schleife ist, diesen Code, der kontrolliert, wie oft die Schleife durchlaufen werden soll, im Kopf der Schleife zu bündeln. Solche Daten sind oft Zähler vom Typ int, die bis zu einem bestimmten Wert herunter oder hoch gezählt werden. Später werden wir noch die Standardklasse Iterator kennenlernen, die benutzt wird, um durch Listenelemente durchzuiterieren.
Eine for-Schleife hat im Kopf
for (init, pred, step){body}

Entsprechend sieht unsere jeweilige erste Schleife, der Ausgabe der Zahlen von 0 bis 9 in der for-Schleifenversion wie folgt aus.
ForTest
class ForTest {
  public static void main(String [] args){

    for (int i=0; i<10; i=i+1){
      System.out.println(i);    
    }  

  }
}

Die Reihenfolge, in der die verschiedenen Teile der for-Schleife durchlaufen wird, wirkt erst etwas verwirrend, ergibt sich aber natürlich aus der Herleitung der for-Schleife aus der vorgeprüften while-Schleife:
Als erstes wird genau einmal die Initialisierung der Schleifenvariablen ausgeführt. Anschließend wird die Bedingung geprüft. Abhängig davon wird der Schleifenrumpf ausgeführt. Als letztes wird die Weiterschaltung ausgeführt, bevor wieder die Bedingung geprüft wird.
Die nun schon hinlänglich bekannte Methode summe stellt sich in der Version mit der for-Schleife wie folgt dar.
Summe3
class Summe3 {
  public static int summe(int n){

    int erg = 0 ;                   // Feld für Ergebnis

    for (int j = n;j>0;j=j-1){      // j läuft von n bis 1     
      erg = erg + j;                // akkumuliere das Ergebnis
    }

    return erg;
  }
}

Beim Vergleich mit der while-Version erkennt man, wie sich die Schleifensteuerung im Kopf der for-Schleife nun gebündelt an einer syntaktischen Stelle befindet.
Die drei Teile des Kopfes einer for-Schleife können auch leer sein. Dann wird in der Regel an einer anderen Stelle der Schleife entsprechender Code zu finden sein. So können wir die Summe auch mit Hilfe der for-Schleife so schreiben, daß die Schleifeninitialisierung und Weiterschaltung vor der Schleife, bzw. im Rumpf durchgeführt wird:
Summe4
class Summe4 {
  public static int summe(int n){

    int erg = 0 ;              // Feld für Ergebnis
    int j   = n ;              // Feld zur Schleifenkontrolle

    for (;j>0;){               // j läuft von n bis 1     
      erg = erg + j;           // akkumuliere das Ergebnis
      j = j-1;                 // verringere Laufzähler  
    }

    return erg;
  }
}

Wie man jetzt sieht, ist die while-Schleife nur ein besonderer Fall der for-Schleife. Obiges Programm ist ein schlechter Programmierstil. Hier wird ohne Not die Schleifensteuerung mit der eigentlichen Anwendungslogik vermischt.

Chapter 3
XML

XML ist eine Sprache, die es erlaubt Dokumente mit einer logischen Struktur zu beschreiben. Die Grundidee dahinter ist, die logische Struktur eines Dokuments von seiner Visualisierung zu trennen. Ein Dokument mit einer bestimmten logischen Struktur kann für verschiedene Medien unterschiedlich visualisiert werden, z.B. als HTML-Dokument für die Darstellung in einem Webbrowser, als pdf- oder postscript-Datei für den Druck des Dokuments und das für unterschiedliche Druckformate. Eventuell sollen nicht alle Teile eines Dokuments visualisiert werden. XML ist zunächst eine Sprache, die logisch strukturierte Dokumente zu schreiben, erlaubt.
Dokumente bestehen hierbei aus den eigentlichen Dokumenttext und zusätzlich aus Markierungen dieses Textes. Die Markierungen sind in spitzen Klammern eingeschlossen.
Beispiel:
Der eigentliche Text des Dokuments sei:
The Beatles White Album

Die einzelnen Bestandteile dieses Textes können markiert werden:
<cd>
  <artist>The Beatles</artist>
  <title>White Album</title>
</cd>

Die XML-Sprache wird durch ein Industriekonsortium definiert, dem W3C (http://www.tfh-berlin.de/~panitz/http://www.w3c.org) . Dieses ist ein Zusammenschluß vieler Firmen, die ein gemeinsames Interesse eines allgemeinen Standards für eine Markierungssprache haben. Die eigentlichen Standards des W3C heißen nicht Standard, sondern Empfehlung (recommendation), weil es sich bei dem W3C nicht um eine staatliche oder überstaatliche Standartisiertungsbehörde handelt.
XML enstand Ende der 90er Jahre und ist abgeleitet von einer umfangreicheren Dokumentenbeschreibungssprache: SGML. Der SGML-Standard ist wesentlich komplizierter und krankt daran, daß es extrem schwer ist, Software für die Verarbeitung von SGML-Dokumenten zu entwickeln. Daher fasste SGML nur Fuß in Bereichen, wo gut strukturierte, leicht wartbare Dokumente von fundamentaler Bedeutung waren, so daß die Investition in teure Werkzeuge zur Erzeugung und Pflege von SGML-Dokumenten sich rentierte. Dies waren z.B. Dokumentationen im Luftfahrtbereich.14
Die Idee bei der Entwicklung von XML war: eine Sprache mit den Vorteilen von SGML zu Entwickeln, die klein, übersichtlich und leicht zu handhaben ist.

3.1  XML-Format

Die grundlegendste Empfehlung des W3C legt fest, wann ein Dokument ein gültiges XML-Dokument ist, die Syntax eines XML-Dokuments. Die nächsten Abschnitte stellen die wichtigsten Bestandteile eines XML-Dokuments vor.
Jedes Dokument beginnt mit einer Anfangszeile, in dem das Dokument angibt, daß es ein XML-Dokument nach einer bestimmten Version der XML Empfehlung ist:
<?xml version="1.0"?>

Dieses ist die erste Zeile eines XML-Dokuments. Vor dieser Zeile darf kein Leerzeichen stehen. Die derzeitig aktuellste und einzige Version der XML-Empfehlung ist die Version 1.0. Ein Entwurf für die Version 1.1 liegt vor. Nach Aussage eines Mitglieds des W3C ist es sehr unwahrscheinlich, daß es jemals eine Version 2.0 von XML geben wird. Zuviele weitere Techniken und Empfehlungen basieren auf XML, so daß die Definition von dem, was ein XML-Dokument ist kaum mehr in größeren Rahmen zu ändern ist.

3.1.1  Elemente

Der Hauptbestandteil eines XML-Dokuments sind die Elemente. Dieses sind mit der Spitzenklammernotation um Teile des Dokuments gemachte Markierungen. Ein Element hat einen Tagnamen, der ein beliebiges Wort ohne Leerzeichen sein kann. Für einen Tagnamen name beginnt ein Element mit <name> und endet mit </name>. Zwischen dieser Start- und Endemarkierung eines Elements kann Text oder auch weitere Elemente stehen.
Es wird für XML-Dokument verlangt, daß es genau ein einziges oberstes Element hat.
Beispiel:
Somit ist ein einfaches XML-Dokument ein solches Dokument, in dem der gesammte Text mit einem einzigen Element markiert ist:
<?xml version="1.0"?>
<myText>Dieses ist der Text des Dokuments. Er ist
mit genau einem Element markiert.
</myText>

Im einführenden Beispiel haben wir schon ein XML-Dokument gesehen, das mehrere Elemente hat. Dort umschließt das Element <cd> zwei weitere Elemente, die Elemente <artist> und <title>. Die Teile, die ein Element umschließt, werden der Inhalt des Elements genannt.
Ein Element kann auch keinen, sprich den leeren Inhalt haben. Dann folgt der öffnenden Markierung direkt die schließende Markierung.
Beispiel:
Folgendes Dokument enthält ein Element ohne Inhalt:
<?xml version="1.0"?>
<skript>
  <page>erste Seite</page>
  <page></page>
  <page>dritte Seite</page>
</skript>

Leere Elemente

Für ein Element mit Tagnamen name, das keinen Inhalt hat, gibt es die abkürzenden Schreibweise: <name/>
Beispiel:
Das vorherige Dokument läßt sich somit auch wie folgt schreiben:
<?xml version="1.0"?>
<skript>
  <page>erste Seite</page>
  <page/>
  <page>dritte Seite</page>
</skript>

Gemischter Inhalt

Die bisherigen Beispiele haben nur Elemente gehabt, deren Inhalt entweder Elemente oder Text waren, aber nicht beides. Es ist aber auch möglich Elemente mit Text und Elementen als Inhalt zu schreiben. Man spricht dann vom gemischten Inhalt (mixed content).
Beispiel:
Ein Dokument, in dem das oberste Element einen gemischten Inhalt hat:
<?xml version="1.0"?>
<myText>Der <landsmann>Italiener</landsmann>
<eigename>Ferdinand Carulli</eigename> war  als Gitarrist 
ebenso wie der <landsmann>Spanier</landsmann> 
<eigename>Fernando Sor</eigename> in <ort>Paris</ort>
ansäßig.</myText>

XML-Dokumente als Bäume

Die wohl wichtigste Beschränkung für XML-Dokumente ist, daß sie eine hierarchische Struktur darstellen müssen. Zwei Elemente dürfen sich nicht überlappen. Ein Element darf erst wieder geschlossen werden, wenn alle nach ihm geöffneten Elemente wieder geschlossen wurden.
Beispiel:
Das folgende ist kein gültiges XML-Dokument. Das Element <bf> wird geschlossen bevor das später geöffnete Element <em> geschlossen worde.
<?xml version="1.0"?>
<illegalDocument>
  <bf>fette Schrift <em>kursiv und fett</bf> 
  nur noch kursiv</em>.
</illegalDocument>

Das Dokument wäre wie folgt als gültiges XML zu schreiben:
<?xml version="1.0"?>
<validDocument>
  <bf>fette Schrift</bf><bf> <em>kursiv und fett</em></bf> 
  <em>nur noch kursiv</em>.
</validDocument>

Dieses Dokument hat eine hierarchische Struktur.
Die hierarchische Struktur von XML-Dokumenten läßt sich sehr schön veranschaulichen, wenn man die Darstellung von XML-Dokumenten in Microsofts Internet Explorer betrachtet.

3.1.2  Attribute

Die Elemente eines XML-Dokuments können als zusätzliche Information auch noch Attribute haben. Attribute haben einen Namen und einen Wert. Syntaktisch ist ein Attribut dargestellt durch den Attributnamen gefolgt von einem Gleichheitszeichen gefolgt von dem in Anführungszeichen eingeschlossenen Attributwert. Attribute stehen im Starttag eines Elements.
Attribute werden nicht als Bestandteils des eigentlichen Textes eines Dokuments betrachtet.
Beispiel:
Dokument mit einem Attribut für ein Element.
<?xml version="1.0"?>
<text>Mehr Information zu XML findet man auf den Seiten
des <link address="www.w3c.org">W3C</link>.</text>

3.1.3  Kommentare

XML stellt auch eine Möglichkeit zur Verfügung, bestimmte Texte als Kommentar einem Dokument zuzufügen. Diese Kommentare werden mit <!-- begonnen und mit --> beendet. Kommentartexte sind nicht Bestandteil des eigentlichen Dokumenttextes.
Beispiel:
Im folgenden Dokument ist ein Kommentar eingefügt:
<?xml version="1.0"?>
<drehbuch filmtitel="Ben Hur">
<akt>
  <szene>Ben Hur am Vorabend des Wagenrennens.
    <!--Diese Szene muß noch ausgearbeitet werden.-->
  </szene>
</akt>
</drehbuch>

3.1.4  Character Entities

Sobald in einem XML-Dokument eine der spitze Klammern < oder > auftaucht, wird dieses als Teil eines Elementtags interpretiert. Sollen diese Zeichen hingegen als Text und nicht als Teil der Markierung benutzt werden, sind also Bestandteil des Dokumenttextes, so muß man einen Fluchtmechanismus für diese Zeichen benutzen. Diese Fluchtmechanismen nennt man character entities. Eine Character Entity beginnt in XML mit dem Zeichen & und endet mit einem Semikolon;. Dazwischen steht der Name des Buchstabens. XML kennt die folgenden Character Entities:
EntityZeichenBeschreibung
&lt;<(less than)
&gt;>(greater than)
&amp;&(ampersant)
&quot;"(quotation mark)
&apos;'(apostroph)
Somit lassen sich in XML auch Dokumente schreiben, die diese Zeichen als Text beinhalten.
Beispiel:
Folgendes Dokument benutzt Character Entities um mathematische Formeln zu schreiben:
<?xml version="1.0"?>
<gleichungen>
  <gleichung>x+1&gt;x</gleichung>
  <gleichung>x*x&lt;x*x*x für x&gt;1</gleichung>
</gleichungen>


3.1.5  CDATA-Sections

Manchmal gibt es große Textabschnitte in denen Zeichen vorkommen, die eigentlich durch character entities zu umschreiben wären, weil sie in XML eine reservierte Bedeutung haben. XML bietet die Möglichkeit solche kompletten Abschnitte als eine sogenannte CData Section zu schreiben. Eine CData section beginnt mit der Zeichenfolge <![CDATA[ und endet mit der Zeichenfolge: ]]>. Dazwischen können beliebige Zeichenstehen, die eins zu eins als Text des Dokumentes interpretiert werden.
Beispiel:
Die im vorherigen Beispiel mit Character Entities beschriebenen Formeln lassen sich innerhalb einer CDATA-Section wie folgt schreiben.
<?xml version="1.0"?>
<formeln><![CDATA[
  x+1>x 
  x*x<x*x*x für x > 1
]]></formeln>


3.1.6  Processing Instructions

In einem XML-Dokument können Anweisung stehen, die angeben, was mit einem Dokument von einem externen Programm zu tun ist. Solche Anweisungen können z.B. angeben, mit welchen Mitteln das Dokument visualisiert werden soll. Wir werden hierzu im nächsten Kapitel ein Beispiel sehen. Syntaktisch beginnt eine processing instruction mit <? und endet mit ?>. Dazwischen stehen wie in der Attributschreibweise Werte für den Typ der Anweisung und eine Referenz auf eine externe Quelle.
Beispiel:
Ausschnitt aus dem XML-Dokument diesen Skripts, in dem auf ein Stylesheet verwiesen wird, daß das Skript in eine HTML-Darstellung umwandelt:
<?xml version="1.0"?>
<?xml-stylesheet 
   type="text/xsl" 
   href="../transformskript.xsl"?>

<skript>
<titelseite>
<titel>Grundlagen der Datenverarbeitung<white/>II</titel>
<semester>WS 02/03</semester>
</titelseite>
</skript>

3.1.7  Namensräume

Die Tagnamen sind zunächst einmal Schall und Rauch. Erst eine externes Programm wird diesen Namen eine gewisse Bedeutung zukommen lassen, indem es auf die Tagnamen in einer bestimmten Weise reagiert.
Da jeder Autor eines XML-Dokuments zunächst vollkommen frei in der Wahl seiner Tagnamen ist, wird es vorkommen, daß zwei Autoren denselben Tagnamen für die Markierung gewählt haben, aber semantisch mit diesem Element etwas anderes ausdrücken wollen. Spätestens dann, wenn verschiedene Dokumente verknüpft werden, wäre es wichtig, daß Tagnamen einmalig mit einer Eindeutigen Bedeutung benutzt wurden. Hierzu gibt es in XML das Konzept der Namensräume.
Tagnamen können aus zwei Teilen bestehen, die durch einen Doppelpunkt getrennt werden:
Hiermit allein ist das eigentliche Problem gleicher Tagnamen noch nicht gelöst, weil ja zwei Autoren den gleichen Präfix und gleichen lokalen Namen für ihre Elemente gewählt haben können. Der Präfix wird aber an einem weiteren Text gebunden, der eindeutig ist. Dieses ist der eigentliche Namensraum. Damit garantiert ist, daß dieser Namensraum tatsächlich eindeutig ist, wählt man als Autor seine Webadresse, denn diese ist weltweit eindeutig.
Um mit Namensräume zu arbeiten ist also zunächst ein Präfix an eine Webadresse zu binden; dies geschieht durch ein Attribut der Art:
xmlns:myPrefix="http://www.myAdress.org/myNamespace".
Beispiel:
Ein Beispiel für ein XML-Dokument, daß den Präfix sep an einem bestimmten Namensraum gebunden hat:
<?xml version="1.0"?>
<sep:skript 
   xmlns:sep="http://www.tfh-berlin.de/~panitz/dv2">
  <sep:titel>Grundlagen der DV 2</sep:titel>
  <sep:autor>Sven Eric Panitz</sep:autor>
</sep:skript>


Die Webadresse eines Namensraumes hat keine eigentliche Bedeutung im Sinne des Internets. Das Dokument geht nicht zu dieser Adresse und holt sich etwa Informationen von dort. Es ist lediglich dazu da, einen eindeutigen Namen zu haben. Streng genommen brauch es diese Adresse noch nicht einmal wirklich zu geben.

3.2  Codierungen

XML ist ein Dokumentenformat, das nicht auf eine Kultur mit einer bestimmten Schrift beschränkt ist, sondern in der Lage ist, alle im Unicode erfassten Zeichen darzustellen, seien es Zeichen der lateinischen, kyrillischen, arabischen, chinesischen oder sonst einer Schrift bis hin zur keltischen Keilschrift. Jedes Zeichen eines XML-Dokuments kann potentiell eines dieser mehrerern zigtausend Zeichen einer der vielen Schriften sein. In der Regel benutzt ein XML-Dokument insbesondere im amerikanischen und europäischen Bereich nur wenige kaum 100 unterschiedliche Zeichen. Auch ein arabisches Dokument wird mit weniger als 100 verschiedenen Zeichen auskommen.
Wenn ein Dokument im Computer auf der Festplatte gespeichert wird, so werden auf der Festplatte keine Zeichen einer Schrift, sondern Zahlen abgespeichert. Diese Zahlen sind traditionell Zahlen die 8 Bit im Speichern belegen, ein sogenannter Byte (auch Oktett). Ein Byte ist in der Lage 256 unterschiedliche Zahlen darzustellen. Damit würde ein Byte ausreichen, alle Buchstaben eines normalen westlichen Dokuments in lateinischer Schrift (oder eines arabischen Dokuments darzustellen). Für ein Chinesisches Dokument reicht es nicht aus, die Zeichen durch ein Byte allein auszudrücken, denn es gibt mehr als 10000 verschiedene chinesische Zeichen. Es ist notwendig, zwei Byte im Speicher zu benutzen, um die vielen chinesischen Zeichen als Zahlen darzustellen.
Die Codierung eines Dokuments gibt nun an, wie die Zahlen, die der Computer auf der Festplatte gespeichert hat, als Zeichen interpretiert werden sollen. Eine Codierung für arabische Texte wird den Zahlen von 0 bis 255 bestimmte arabische Buchstaben zuordnen, eine Codierung für deutsche Dokumente wird den Zahlen 0 bis 255 lateinische Buchstaben inklusive deutscher Umlaute und dem ß zuordnen. Für ein chinesisches Dokument wird eine Codierung benötigt, die den 65536 mit 2 Byte darstellbaren Zahlen jeweils chinesische Zeichen zuordnet.
Man sieht, daß es Codierungen geben muß, die für ein Zeichen ein Byte im Speicher belegen, und solche, die zwei Byte im Speicher belegen. Es gibt darüberhinaus auch eine Reihe Mischformen, manche Zeichen werden durch ein Byte andere durch 2 oder sogar durch 3 Byte dargestellt.
Im Kopf eines XML-Dokuments kann angegeben werden, in welcher Codierung das Dokument abgespeichert ist.
Beispiel:
Dieses Skript ist in einer Codierung gespeichert, die für westeuropäische Dokumente gut geeignet ist, da es für die verschiedenen Sonderzeichen der westeuropäischen Schriften einen Zahlenwert im 8-Bit-Bereich zugeordnet hat. Die Codierung mit dem Namen: iso-8859-1. Diese wird im Kopf des Dokuments angegeben:
<?xml version="1.0" encoding="iso-8859-1" ?>
<skript><kapitel>blablabla</kapitel></skript>

Wird keine Codierung im Kopf eines Dokuments angegeben, so wird als Standardcodierung die sogenannte utf-8 Codierung benutzt. In ihr belegen lateinische Zeichen einen Byte und Zeichen anderer Schriften (oder auch das Euro Symbol) zwei bis drei Bytes.
Eine Codierung, in der alle Zeichen mindestens mit zwei Bytes dargestellt werden ist: utf-16, die Standardabbildung von Zeichen, wie sie im Unicode definiert ist.

3.3  HTML

Im ersten Semester dieser Vorlesung wurde bereits HTML vorgestellt. HTML sieht äußerlich zunächst XML sehr ähnlich. Es gibt ebenso die Elemente in Spitzen Klammern und Elemente können auch Attribute haben. In HTML gibt es eine feste vordefinierte Anzahl von Elementen, die vom Webbrowser als Anweisung, wie das Dokument darzustellen ist, interpretiert wird. HTML ist älter als XML und ebenso wie XML aus SGML abgeleitet. Während ein XML-Dokument die logische Struktur beschreibt, beschreibt ein HTML-Dokument die Visualisierung eines Dokuments.
Leider sind in HTML einige Dinge erlaubt, die HTML-Dokumente zu ungültigen XML-Dokumenten machen. Dieses sind vor allen:
Ein neuerer HTML-Dialekt behebt die Unstimmigkeiten, die verhindern, daß HTML-Dokumente gültige XML-Dokumente sind: XHTML. Es gibt Werkzeuge, die HTML-Dokumente in XHTML-Dokumente und damit auch in XML-Dokumente konvertieren.
In der folgenden Tabelle sind die gebräuchlichsten Tagnamen für HTML-Elemente aufgeführt.
ElementnameEigenschaft
htmloberstes Element
titleElemente für Titelzeile
bodyElement für Dokumentinhalt
h1Hauptüberschrift
h2Unterüberschrift
h3zweite Unterüberschrift
h4weitere Unterüberschrift
pAbsatz
brZeilenumbruch
centerzentrierter Text
bFettdruck
itKursivdruck
emHervorhebung
ulPunktliste
liListenelement
tableTabelle
trTabellenzeile
tdTebellenzelle
<a href=" http://myAdresse/" >Link zu einer Adresse
<img src=" myPicture.gif" >Einbindung eines Bildes
Am einfachsten ist es HTML mit einem WYSIWYG-Editor15 zur schreiben. Hierzu gibt es eine Vielzahl von Programmen; auch der Webbrowser Netscape ist in der Lage HTML-Dokumente zu edieren.

3.3.1  Frames

Eine häufig auf Webseiten angewendete Technik ist, mehrere ganze HTML-Seiten nebeneinander in einem Browserfenster anzuzeigen. Hierzu gibt es ein besonderes Konstrukt in HTML, das über zwei Elemente ausgedrückt wird: <FRAMESET> und <Frame>. In einem Frameset wird definiert wieviele HTML-Seiten auf welche Weise nebeneinander gleichzeitig darzustellenen sind. Die Frameelemente verweisen dann auf die entsprechenden Webseiten.
Beispiel:
Folgender HTML-Code definiert eine Frameseite mit zwei Frames, einen oberen, der 30 Prozent der Gesamtseite ausmacht und einen unteren, der die restlichen 70 Prozent ausmacht. Zwischen diesen beiden Seiten gibt es keinen Trennrand. Dieses wird durch das Attribut border="0" ausgedrückt.
<html>
<head>
  <title>Testseite für Frames</title>
</head>

<frameset rows="30%, 70%" border="0">
<frame src="obereSeite.html" name="oben"></frame>
<frame src="untereSeite.html" name="unten"></frame>
</frameset>                           
</html>

Wenn es die Dateien obereSeite.html und untereSeite.html im Dateisystem gibt, so zeigt die Frameseite diese beiden beim Öffnen im Browser an.
Zusätzlich ist den beiden Frames noch das Attribut name vergeben worden. Hier ist diesen ein eindeutiger frei gewählter Name zugeordnet worden. Dieses ermöglicht Hyperlinks so zu definieren, das die Seite des Links in einem bestimmten Frame geöffnet wird und nicht als komplett neue Seite, wie es standardmäßig der Fall ist. Hierzu ist mit einem Attribut target im Element a des Hyperlinks der Name des Frames anzugeben, in dem die Seite des Links geöffnet werden soll.
<html><head><title>obere Seite</title>
<body>hier kommt 
ein <a href="http://www.tfh-berlin.de" target="unten">Link</a>, 
der im unteren Frame geöffnet wird.</body>
</head></html>


Als typische Anwendung von Frames wird ein Frame als Navigationsseite benutzt, auf der die Links zu allen Seiten einer Website gesammelt sind und der andere Frame wird benutzt, um die Links deer Navigationsseite anzuzeigen, sofern sie gedrückt werden. Die Navigationsseite wird dabei in der Regel entweder am linken Rand oder über der eigentlichen Inhaltsseite angezeigt.

3.3.2  Sonderzeichen

Auch in HTML-Elemente ist es möglich internationale Zeichen zu verwenden. Leider benutzt HTML ursprünglich nicht denselben Mechanismus wie XML, indem auf gleiche Weise eine Codierung der Zeichen angegeben wird.

Character Entities

HTML kennt im Gegensatz zu den wenigen Character Entities in XML eine große Anzahl solcher Fluchtmechanismen für die unterschiedlichsten Zeichen. So können in einem deutschen Text Umlaute wie mit den folgenden Entities umschrieben werden:
&uuml;u Umlautü
&Uuml;U UmlautÜ
&auml;a Umlautä
&Auml;A UmlautÄ
&ouml;o Umlautö
&Ouml;O UmlautÖ
&szlig;sz-Ligaturß
Diese Umschreibung ist bei Tippen eines Textes von Hand sehr umständlich.

Codierung festlegen

In HTML läßt sich die Codierung eines Dokuments durch ein Element meta angeben:
<html>  
<head>
  <meta http-equiv="content-type"
       content="text/html; charset=ISO-8859-1">
</head>
<body>
Deutscher Text mit Umlauten ü Ü ö Ö ä Ä ß
</body>
</html>

Damit können Umlaute direkt im Text eingetippt werden und brauchen nicht durch character entities umschrieben zu werden.

3.3.3  CSS

In HTML kann das Layout der Seite relativ genau beschrieben werden. Es kann die Hintergrundfarbe definiert werden, es kann der Schrifttyp festgelegt werden oder auch die Schriftgröße kann festgelegt werden. Wenn man eine komplette Website schreibt, die eventuell viele hundert HTML-Seiten umfasst, z.B. der Webauftritt einer großen Versandhausfirma, so ist es ratsam, bestimmte Stilvorgaben, über Farben und Schriften nicht in jeder Seite einzeln zu definieren, sondern getrennt in einer Stildatei, auf die alle HTML-Seiten verweisen. Soll der gesammte Webauftritt optisch verändert werden, z.B.  ein neues Farbschema oder andere Schriften benutzt werden, so brauch dann nur die eine Datei, in der der Stil definiert ist, abgeändert werden. Die eigentlichen HTML-Seiten bleiben davon dann unberührt. Für HTML gibt es eine entsprechendes Stilformat: CSS (cascading style sheet).
Eine CSS-Datei definiert den Stil der HTML-Seiten. in den eigentlichen HTML-Seiten wird dieser Stil schließlich nur noch importiert.
Wir geben ein kleines Beispiel für den Einsatz eines CSS. Der interessierte Student sei auf eines der zahlreichen Tutorials im Netz oder die recommendation des W3C verwiesen.
Beispiel:
Folgende kleines CSS-Datei definiert für die Dokumente einen roten Hintergrund und schwarze Schrift. Text in Elementen div wird im Blocksatz gesetzt, Fraben für Links gesetzt. Schließlich wird noch ein neues Stilelement Kasten definiert. Diese Datei wird unter den Namen myStyle.css abgespeichert.
body { background:#ff0000 
     ; color:#000000} 


.kasten { background:#999999
        ; color: black
        ; border-width: thick
        ; border-color:#000000
        ; border-style:double }
 
a:link    { color: blue }
a:visited { color: #ffffff }
a:hover   { color: green }
a:active  { color: lime }

div { text-align:justify }

Diese Stilbeschreibung kann nun in HTML-Dokumenten benutzt werden, indem auf die CSS-Datei verwiesen wird.
<html>
<head>
  <title>CSS Test</title>
   <link href="myStyle.css" rel="stylesheet" type="text/css" />
    <meta http-equiv="content-type"
          content="text/html; charset=ISO-8859-1" /> 
 </head>
<body>
<div>Diese Seite testet den Einsatz von CCS. Sie verweist in 
einem Element <em class="kasten">link</em> auf 
die CSS-Datei, die den Stil  bestimmen soll. Wer mehr über 
CSS erfahren will sei auf das 
<a href="http://www.w3.org">W3C</a> verwiesen.
</div>
</body>
</html>

Die Anzeige dieser Seite im Netscape ist in Abbildung zu bewundern.
Figure
Figure 3.1: Anzeige der HTML, deren Stil per CSS-Skript formuliert wurde.

3.4  SVG

Wir haben bisher XML-Dokumente geschrieben, um einen Dokumenttext zu strukturieren. Die Strukturierungsmöglichkeiten von XML machen es zu einem geeigneten Format, um beliebige Strukturen von Daten zu beschreiben. Eine gängige Form von Daten sind Graphiken. SVG (scalable vector graphics) sind XML-Dokumente, die graphische Elemente beschreiben. Zusätzlich kann in SVG ausgedrückt werden, ob und in welcher Weise Graphiken animiert sind.
SVG-Dokumente sind XML-Dokumente mit bestimmten festgelegten Tagnamen. Auch SVG ist dabei ein Standard, der vom W3C definiert wird.
Beispiel:
Folgendes kleine SVG-Dokument definiert eine Graphik, die einen Kreis, ein Viereck und einen Text enthält.
<?xml version="1.0" encoding="ISO-8859-1"?>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
 <ellipse cx="100" cy="100" rx="48" ry="90" fill="limegreen" />
 <text x="20" y="115">SVG Textobjekt</text>
 <rect x="50" y="50" width="50" height="60" fill="red"/>
</svg>

Für ausführliche Informationen über die in SVG zur Verfügung stehenden Elemente sei der interessierte Student auf eines der vielen Tutorials im Netz oder direkt auf die Seiten des W3C verwiesen.

3.5  XSLT

XML-Dokumente enthalten keinerlei Information darüber, wie sie visualisiert werden sollen. Hierzu kann man getrennt von seinem XML-Dokument ein sogenanntes Stylesheet schreiben. XSL ist eine Sprache zum Schreiben von Stylesheets für XML-Dokumente. XSL ist in gewisser Weise eine Programmiersprache, deren Programme eine ganz bestimmte Aufgabe haben: XML Dokumente in andere XML-Dokumente zu transformieren. Die häufigste Anwendung von XSL dürfte sein, XML-Dokumente in HTML-Dokumente umzuwandeln.
Beispiel:
Wir werden die wichtigsten XSLT-Konstrukte mit folgendem kleinem XML Dokument ausprobieren:
<?xml version="1.0" encoding="iso-8859-1" ?>
<?xml-stylesheet type="text/xsl" href="cdTable.xsl"?>
<cds>
 <cd>
  <artist>The Beatles</artist>
  <title>White Album</title>
  <label>Apple</label>
 </cd>
 <cd>
  <artist>The Beatles</artist>
  <title>Rubber Soul</title>
  <label>Parlophone</label>
 </cd>
 <cd>
  <artist>Duran Duran</artist>
  <title>Rio</title>
  <label>Tritec</label>
 </cd>
 <cd>
  <artist>Depeche Mode</artist>
  <title>Construction Time Again</title>
  <label>Mute</label>
 </cd>
 <cd>
  <artist>Yazoo</artist>
  <title>Upstairs at Eric's</title>
  <label>Mute</label>
 </cd>
 <cd>
  <artist>Marc Almond</artist>
  <title>Absinthe</title>
  <label>Some Bizarre</label>
 </cd>
 <cd>
  <artist>ABC</artist>
  <title>Beauty Stab</title>
  <label>Mercury</label>
 </cd>
</cds>


3.5.1  Gesamtstruktur

XSLT-Skripte sind syntaktisch auch wieder XML-Dokumente. Ein XSLT-Skript hat feste Tagnamen, die eine Bedeutung für den XSLT-Prozessor haben. Diese Tagnamen haben einen festen definierten Namensraum. Das äußerste Element eines XSLT-Skripts hat den Tagnamen stylesheet. Damit hat ein XSLT-Skript einen Rahmen der folgenden Form:
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>


Einbinden in ein XML-Dokument

Wir können mit einer Processing-Instruction am Anfang eines XML-Dokumentes definieren, mit welchem XSLT Stylesheet es zu bearbeiten ist. Hierzu wird als Referenz im Attribut href die XSLT-Datei angegeben.
<?xml version="1.0" encoding="iso-8859-1" ?>
<?xml-stylesheet type="text/xsl" href="cdTable.xsl"?>
<cds>
 <cd>........

3.5.2  Templates (Formulare)

Das wichtigste Element in einem XSLT-Skript ist das Element xsl:template. In ihm wird definiert, wie ein bestimmtes Element transformiert werden soll. Es hat schematisch folgende Form:
<xsl:template match="Elementname">
  zu erzeugender Code
</xsl:template >
Beispiel:
Folgendes XSLT-Skript transformiert die XML-Datei mit den CDs in eine HTML-Tabelle, in der die CDs tabellarisch aufgelistet sind.
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- Startregel für das ganze Dokument. -->
<xsl:template match="/">
  <html><head><title>CD Tabelle</title></head>
    <body>
      <xsl:apply-templates/>
    </body>
  </html>   
</xsl:template>


<!-- Regel für die CD-Liste. -->
<xsl:template match="cds">
  <table border="1">
    <tr><td><b>Interpret</b></td><td><b>Titel</b></td></tr>
    <xsl:apply-templates/>
  </table>
</xsl:template>

<xsl:template match="cd">
  <tr><xsl:apply-templates/></tr>
</xsl:template>

<xsl:template match="artist">
  <td><xsl:apply-templates/></td>
</xsl:template>

<xsl:template match="title">
  <td><xsl:apply-templates/></td>
</xsl:template>

<!-- Regel für alle übrigen Elemente. 
     Mit diesen soll nichts gemacht werden -->
<xsl:template match="*">
</xsl:template>

</xsl:stylesheet>

Öffnen wir nun die XML Datei, die unsere CD-Liste enthält im Webbrowser, so wendet er die Regeln des referenzierten XSLT-Skriptes an und zeigt die so generierte Webseite wie in Abbildung zu sehen an.
Figure
Figure 3.2: Anzeige der per XSLT-Skript generierten HTML-Seite.
Läßt man sich vom Browser hingegen den Quelltest der Seite anzeigen, so wird kein HTML-Code angezeigt sondern der XML-Code.

3.5.3  Auswahl von Teildokumenten

Das Element xsl:apply-templates veranlasst den XSLT-Prozessor die Elemente des XML Ausgangsdokuments weiter mit dem XSL Stylesheet zu bearbeiten. Wenn dieses Element kein Attribut hat, wie in unseren bisherigen Beispielen, dann werden alle Kinder berücksichtigt. Mit dem Attribut select lassen sich bestimmte Kinder selektieren, die in der Folge nur noch betrachtet werden sollen.
Beispiel:
Im folgenden XSL Element selektieren wir für cd-Elemente nur die title und artist Kinder und ignorieren die label Kinder.
<!-- für das Element "cd" -->
<xsl:template match="cd">
  <!--erzeuge ein Element "tr" -->
  <tr>
     <!-- wende das stylesheet weiter an auf die Linderelemente
     "title" -->
     <xsl:apply-templates select="title"/>
     <!-- wende das stylesheet weiter an auf die Linderelemente
     "artist" -->

     <xsl:apply-templates select="artist"/>
  </tr>
</xsl:template>

3.5.4  Sortieren von Dokumentteilen

XSLT kennt ein Konstrukt, um zu beschreiben, daß bestimmte Dokumente sortiert werden sollen nach bestimmten Kriterien. Hierzu gibt es das XSLT-Element xsl:sort. In einem Attribut select wird
angegeben, nach welchen Elementteil sortiert werden soll.
Beispiel:
Zum Sortieren der CD-Liste kann mit xsl:sort das Unterelement artist als Sortierschlüssel bestimmt werden.
<xsl:template match="cds">
  <table border="1">
    <tr><td><b>Interpret</b></td><td><b>Titel</b></td></tr>
    <xsl:apply-templates select="cd">
      <xsl:sort select="artist"/> 
    </xsl:apply-templates>
  </table>
</xsl:template>

3.5.5  Weitere Konstrukte

XSLT kennt noch viele weitere Konstrukte, so z.B. für bedingte Ausdrücke wie in herkömmlichen Programmiersprachen durch einen if-Befehl und explizite Schleifenkonstrukte, Möglichkeiten das Ausgangsdokument, mehrfach verschiedentlich zu durchlaufen, und bei einem Element nicht nur auf Grund seines Elementnamens zu reagieren, sondern auch seine Kontext im Dokument zu berücksichtigen. Der interessierte Leser sei auf eines der vielen Tutorials im Netz oder auf die Empfehlung des W3C verwiesen.

3.6  DTD und Schema

Wir haben bereits verschiedene Typen von XML-Dokumenten kennengelernt: XHTML-, XSLT- und SVG-Dokumente. Solche Typen von XML-Dokumenten sind dadurch gekennzeichnet, daß sie gültige XML-Dokumente sind, in denen nur bestimmte vordefinierte Tagnamen vorkommen und das auch nur in einer bestimmten Reihenfolge. Solche Typen von XML-Dokumenten können mit einer Typbeschreibungssprache definiert werden. Für XML gibt es zwei solcher Typbeschreibungssprachen: DTD und Schema.

3.6.1  DTD

DTD (document type description) ermöglicht es zu formulieren, welche Tags in einem Dokument vorkommen sollen. DTD ist keine eigens für XML erfundene Sprache, sondern aus SGML geerbt.
DTD-Dokumente sind keine XML-Dokumente, sondern haben eine eigene Syntax. Wir stellen im einzelnen diese Syntax vor:
Beispiel:
Ein Beispiel für eine DTD, die ein Format für eine Rezeptsammlung definiert.
<!ELEMENT collection (description,recipe*)>

<!ELEMENT description ANY>

<!ELEMENT recipe (title,ingredient*,preparation
                 ,comment?,nutrition)>

<!ELEMENT title (#PCDATA)>

<!ELEMENT ingredient (ingredient*,preparation)?>
<!ATTLIST ingredient name CDATA #REQUIRED
                     amount CDATA #IMPLIED
                     unit CDATA #IMPLIED>

<!ELEMENT preparation (step*)>

<!ELEMENT step (#PCDATA)>

<!ELEMENT comment (#PCDATA)>

<!ELEMENT nutrition EMPTY>
<!ATTLIST nutrition fat CDATA #REQUIRED
                    calories CDATA #REQUIRED
                    alcohol CDATA #IMPLIED>

Aufgabe 5   Schreiben Sie ein XML Dokument, daß nach den Regeln der obigen DTD gebildet wird.

3.6.2  Schema

Daß DTDs keine XML-Dokumente sind, hat die Erfinder von XML im Nachhinein recht geärgert. Außerdem war für die vorgesehen Zwecke im Bereich Datenverwaltung mit XML, die Ausdrucksstärke von DTD zum Beschreiben der Dokumenttypen nicht mehr ausdruckstark genug. Es läßt sich z.B.  nicht formulieren, daß ein Attribut nur Zahlen als Wert haben darf. Aus diesen Gründen wurde eine Arbeitsgruppe ins Leben gerufen, die einen neuen Standard definieren sollte, der DTDs langfristig ersetzen kann. Die neue Sprache sollte in XML Syntax notiert werden und die bei DTDs vermissten Ausdrucksmittel beinhalten. Diese neue Typbneschreibungssprache heißt Schema und ist mitlerweile im W3C verabredet worden. Leider ist das endgültige Dokument über Schema recht komplex und oft schwer verständlich geworden. Wir wollen in dieser Vorlesung nicht näher auf Schema eingehen.

Chapter 4
Objektorientierte Programmierung

4.1  Objektorientierung

Wir haben Java bisher als eine rein traditionelle prozedurale Programmiersprache betrachtet. Eines der Hauptmerkmale von Java, ist sein objektorientiertes Paradigma.

4.1.1  Modellierung von Objekten

Die Idee der Objektorientierung ist, Daten und Unterprogramme, die inhaltlich eine Einheit bilden in einem Objekt zu bündeln. Hierzu schreibt man Klassen, die Felder für alle Daten enthält, die zu einem Objekt gehören sollen:
Beispiel:
Folgende Klasse modelliert Objekte des Typs Buch. Ein Buch ist dadurch gekennzeichnet, daß es einen Titel, einen Autor und einen Preis hat. Autorname und Titel sind als Feldern des Typs String modelliert, der Preis als ein Feld des Typs int.
Buch1
class Buch1{
  String titel;
  String autor;
  int    preis;
}

Obige Klasse beschreibt wie Objekte des Typs Buch1 aussehen. Sie fassen jeweils drei Felder zusammen.
Aufgabe 6   Schreiben Sie eine Klasse Person1, die eine Person modelliert. eine Person soll einen Namen, einen Vornamen, eine Straße, eine Hausnummer, eine Postleitzahl und einen Ort als Daten enthalten.

4.1.2  Konstruktoren

Bisher haben wir beschrieben, wie die Objekte einer Klasse aussehen. Jetzt müssen wir noch beschreiben, wie ein Objekt konstruiert werden kann. Hierzu wird in der Klasse noch eine spezielle Methode geschrieben, der Konstruktor. Der Konstruktor gibt an, wie ein Objekt einer Klasse aus einzelenen Daten konstruiert werden kann. Ein Konstruktor hat in Java immer genau den Namen der Klasse.
Ein Konstruktor sieht einer Methode sehr ähnlich. Er hat einen Kopf, in dem steht, was für Argumente übergeben werden und einen Rumpf, der in geschweiften Klammern eingeschlossen ist. In diesem Rumpf befinden sich Javabefehle. Typischer Weise werden im Rumpf einer Methode die dem Konstruktor übergebenen Argumente in die Felder des Objektes abgespeichert.
Beispiel:
Folgende Klasse fügt der Klasse Buch1 aus dem letzten Abschnitt noch einen Konstruktor hinzu:
Buch2
class Buch2 {
  //die Felder der Klasse
  String titel;
  String autor;
  int    preis;

  //der Konstruktor. er erhält Daten für die Felder und weist
  //diese Daten den Feldern zu.
  Buch2(String derTitel,int derPreis,String derAutor){
    titel=derTitel;
    autor=derAutor;
    preis=derPreis;
  }
}

Aufgabe 7   Schreiben Sie eine Klasse Person2, die zusätzlich zu den Feldern aus ihrer Klasse Person1 noch einen Konstruktor enthält, der die Felder der Klasse mit als Argumente übergebenen Daten füllt.

4.1.3  Benutzen von Objekten

Wir sind jetzt soweit, daß wir in einer Klasse beschrieben haben, was für Daten die Objekte dieses Typs enthalten und wie Objekte konstruiert werden können. Klassen die einen Objekttyp beschreiben definieren einen neuen Javatyp. Wir können den Typ Buch2 jetzt genauso benutzen, wie den Typ String. Wir können Felder des Typs Buch2 definieren, oder Parameter vom Typ Buch2 für Methoden vorsehen.
Jetzt müssen wir nur noch Objekte erzeugen und und mit ihnen arbeiten.

Erzeugen von Objekten

Wenn wir eine Klasse mit einem Konstruktor geschrieben haben, so kann mit dem Wort new der Konstruktor benutzt werden. Dem Wort new folgt dabei der Name der Klasse von dem ein neues Objekt erzeugt werden soll, gefolgt schließlich von in runden Klammern eingeschlossenen Argumenten, die dem Konstruktor übergeben werden sollen.
Beispiel:
In folgender Klasse schreiben wir eine Hauptmethode, die in zwei Feldern vom Typ Buch2 jeweils ein neues Objekt speichert.
ErzeugeBuch2
class ErzeugeBuch2 {
  public static void main(String [] _){
    Buch2 b1 = new Buch2("Zettels Traum",150,"Arno Schmidt");
    Buch2 b2 = new Buch2("Making History",15,"Stephen Fry");
  }
}

Die verschiedenen Objekte einer Klasse sind unabhängig voneinander. Im obigen Beispel werden zwei Bücher erzeugt. Diese beiden Bücher haben eigene Titel, Preise und Autornamen. Sie sind wie zwei Objekte des Typs String oder zwei Zahlen voneinander unabhängig.
Aufgabe 8   Erzeugen Sie in einer Testklasse zwei Objekte des Typs Person2.

Zugriff auf Daten eines Objektes

Wir haben jetzt gelernt, wie Objekte erzeugt werden. Jetzt wollen wir für Objekte wieder auf ihre einzelnen Daten zugreifen können, oder diese eventuell verändern. Hierzu hat Java eine Punktnotation. Wenn man auf einzelne Eigenschaften eines Objektes zugreifen will, so schreibt man in Java einen Punkt gefolgt von der Eigenschaft des Feldes.
Beispiel:
In folgender Klasse erzeugen wir zwei Buchobjekte. Dann werden einzelne Eigenschaften dieser Objekte ausgegeben und schließlich wird für ein Objekt der Preis um 8 Prozent erhöht:
BenutzeBuch2
class BenutzeBuch2 {
 public static void main(String [] _){
    Buch2 b1 = new Buch2("Zettels Traum",150,"Arno Schmidt");
    Buch2 b2 = new Buch2("Making History",15,"Stephen Fry");

    System.out.println("Das Buch "+b1.titel+" von "+b1.autor
                     + " kostet "+b1.preis+" Euro.");
    System.out.println("Das Buch "+b2.titel+" von "+b2.autor
                     + " kostet "+b2.preis+" Euro.");

    b1.preis = b1.preis+(b1.preis*8/100);
    System.out.println("Das Buch "+b1.titel+" von "+b1.autor
                     + " kostet jetzt "+b1.preis+" Euro.");
    System.out.println("Das Buch "+b2.titel+" von "+b2.autor
                     + " kostet weiterhin "+b2.preis+" Euro.");
  }
}

Wie man sieht, funktionieren Felder eines Objektes genauso, wie wir bisher Felder benutzt haben. Man kann ihre Werte auslesen und verändern. Man muß lediglich dazu notieren zu welchen Objekt das Feld gehört.
Aufgabe 9   Schreiben Sie ein kleines Testprogramm, daß Ihre Klasse Person2 benutzt. Erzeugen Sie zwei Objekte des Typs Person2. Geben Sie einige der Daten dieser Objekte auf dem Bildschirm aus. Ändern Sie dann die Adresse einer der Personen und geben Sie die neuen Daten dieser Person auf dem Bildschirm aus.

4.1.4  Methoden für Objekte

Schreiben von Methoden für Objekte

Der eigentliche Clou der Objektorientierung ist, daß zu Objekten nicht nur Daten gehören, die in Feldern gespeichert sind, sondern auch Methoden, die auf diesen Daten operieren. Hierzu kann man in einer Klasse Methoden schreiben. Dabei läßt man das Attribut static, daß wir bisher vor Methoden geschrieben haben fort. Damit bezieht sich eine Methode nur auf ein bestimmtes Objekt. Sie rechnet dann nur noch auf den Daten eines einzelnen Objektes.
Beispiel:
Wir ergänzen unsere Klasse zur Modellierung von Büchern um drei Methoden. Eine Methode berechnet den Preis des Objektes in Dollar. Die andere Methode erhöht den Preis um einen bestimmten Prozentsatz, die letzte Methode gibt alle Daten eines Buches als String zurück.
Buch
class Buch {
  //die Felder der Klasse
  String titel;
  String autor;
  int    preis;

  //der Konstruktor. er erhält Daten für die Felder und weist
  //diese Daten den Feldern zu.
  Buch(String derTitel,int derPreis,String derAutor){
    titel=derTitel;
    autor=derAutor;
    preis=derPreis;
  }

  //Methoden für die Objekte
  public int preisInDollar(){
    return preis+preis*17/100;
  }

  public void erhöhePreisUmProzent(int prozent){
    preis=preis+preis*prozent/100;
  }

  public String toString(){
    return 
     "Das Buch "+titel+" von "+autor+ " kostet "+preis+" Euro.";
  }
}

Wie man sieht können die Methoden, die nicht statisch sind, genauso alle Merkmale der statischen Methoden haben. Sie können Parameter haben (wie die Methode erhöhePreisUmProzent), sie können eine Rückgabewert berechnen (wie die Methoden preisInDollar und toString). Aber sie können auch die Werte eines Objektes verändern, soe wie es die Methode erhöhePreisUmProzent macht.
Aufgabe 10   Schreiben Sie eine Klasse Person, indem Sie Ihre Klasse Person2 um zwei Methoden erweitern.

Benutzung von Methoden auf Objekten

Nachdem wir für Objekte Methoden geschrieben haben, wollen wir diese natürlich auch benutzen. Hierzu wird die gleiche Syntax benutzt, wie für den Zugriff auf die Felder eines Objektes, nämlich die Punktnotation. Der Punkt trennt das Objekt von dem Methodenaufruf für das Objekt.
Beispiel:
BenutzeBuch
class BenutzeBuch{
  public static void main(String [] _){
    Buch b1 = new Buch("Zettels Traum",150,"Arno Schmidt");
    Buch b2 = new Buch("Making History",15,"Stephen Fry");
    
    System.out.println(b1.toString());
    System.out.println(b2.toString());

    b1.erhöhePreisUmProzent(8);
    System.out.println(b1.toString());

    System.out.println
     ("Das Buch "+b1.titel+" kostet in Dollar: "
      +b1.preisInDollar()+"USD");
  }  
}

Wie man sieht, bezieht sich eine Methode tatsächlich auf genau ein Objekt und operiert nur auf dessen Daten.
Aufgabe 11   Schreiben Sie eine Testklasse für Ihre Klasse Person, so daß Sie die Methoden der Klasse Person alle einmal aufgerufen haben.

4.1.5  Objekte, die Objekte enthalten

Klassen, die wir für bestimmte Objekttypen schreiben, definieren genauso Typen, wie die Typen, die in Java schon vordefiniert sind. Die Klassen Buch und Person können jetzt also genauso als Typ benutzt werden, wie z.B. die Klasse String.
Beispiel:
Wir definieren eine neue Klasse, die ausdrückt, daß ein Buch von einer bestimmten Person ausgeliehen ist:
Buchausleihe
class Buchausleihe {
  Buch buch;
  Person ausleiher;
  int rückgabeTag;
  int rückgabeMonat;
  int rückgabeJahr;

  Buchausleihe(Buch b,Person a,int tag,int monat,int jahr){
    buch=b;
    ausleiher=a;
    rückgabeTag=tag;    
    rückgabeMonat=monat;
    rückgabeJahr=jahr;
  }
 
  public String toString(){
    return ausleiher+" hat das Buch "+buch
        +" ausgeliehen. Rückgabe ist der "
        +rückgabeTag+"."+rückgabeMonat+"."+rückgabeJahr;
  }

  void verlängerteAusleihe(){
    if (rückgabeMonat==12){
      rückgabeMonat=1;
      rückgabeJahr=rückgabeJahr+1;
    }else{
      rückgabeMonat=rückgabeMonat+1;
    }
  }   
}

Aufgabe 12   Schreiben Sie ein kleines Testprogramm, das Objekte des Typs Buchausleihe erzeugt und Methoden darauf anwendet.

4.1.6  Die Java Standardklassen String

Wir haben bisher den Typ String benutzt, ohne uns darüber Gedanken zu machen, daß es sich dabei auch um eine Klasse handelt, und die einzelnen Daten der Klasse String auch Objekte sind, auf die Methoden aufgerufen werden können. String ist nichts weiteres als eine Klasse, die nicht wir geschrieben haben, sondern die Entwickler der Sprache Java für uns geschrieben haben. Der einzige Unterschied zu Klassen, die wir schreiben ist, daß Stringobjekte nicht durch das new-Konstrukt erzeugt werden, sondern durch eine eigene Notation, in der der Text des String-Objekts einfach in Anführungszeichen eingeschlossen wird. Wenn wir in die Javadokumentation schauen, stellen wir fest, daß es eine ganze Reihe von unterschiedlichen Methoden für die Klasse String gibt, z.B. zur Berechnung der Länge eines Textes, oder um Teiltexte zu selektieren.
Beispiel:
In der folgenden Klasse testen wir einige der Methoden, die für String-Klasse definiert sind:
StringTest
class StringTest {

  public static void main(String [] _){
    String str1 = "hallo da draußen";

    System.out.println(str1.length());
    String str2 = str1.substring(2,6);
    System.out.println(str2);
    System.out.println(str2.length());

    System.out.println(str1.toUpperCase());
    System.out.println(str1.toUpperCase().length());
  }
}

Aufgabe 13   Suchen Sie sich aus der Javadokumentation zur Klasse String weitere Methoden heraus und schreiben Sie ein Testprogramm, daß diese Methoden ausprobiert.

4.1.7  Erweitern von Klassen

Ein weiteres Schlüsselkonzept der objektorientierten Programmierung erlaubt es, Klassen, die Objekte beschreiben, um zusätzliche Information zu erweitern. Diese zusätzlichen Informationen können weitere Datenfelder, oder zusätzliche Methoden sein.

Definition von Unterklassen

Hierzu schreibt man eine neue Klasse, die eine bestehende Klasse erweitert. Man spricht von einer Unterklasse. Die Unterklasse hat alle Eigenschaften der Oberklasse und zusätzlich vielleicht ein paar weitere Eigenschaften. In Java gibt man durch eine extends-Klausel nach dem Klassennamen an, daß die neue Klasse eine bestehende Klasse erweitert.
Der erste Befehl im Konstruktor einer Unterklasse muß den Konstruktor der Oberklasse aufrufen. Damit ist gewährleistet, daß bevor man ein Objekt um zusätzliche Eigenschaften erweitert, ersteinmal das zu erweiternde Objekt erzeugt werden muß. In Java wird der Konstruktor der Oberklasse durch den Befehl super aufgerufen. Diesem gibt man die Argumente zum Konstruieren der Superklasse mit.
Beispiel:
Wir schreiben eine Klasse UebersetztesBuch, die die Klasse Buch erweitert, und zwei zusätzliche Eigenschaft hat, nämlich den Namen des Übersetzers und die Sprache des Originals:
UebersetztesBuch
class UebersetztesBuch extends Buch {
  String übersetzer;
  String spracheDesOriginals;

  UebersetztesBuch
      (String derTitel,int derPreis,String derAutor
      ,String derÜbersetzer,String sprache){
    super(derTitel,derPreis,derAutor);
    übersetzer = derÜbersetzer;
    spracheDesOriginals = sprache;
  }
}

Hier ist UebersetztesBuch die Unterklasse, die die Oberklasse Buch erweitert.
Aufgabe 14   Schreiben Sie eine Klasse Student, die die Klasse Person um ein weiteres Feld matrikelNr erweitert.

Benutzung von Unterklassen

Objekte einer Unterklasse können vollständig wie Objekte der Oberklasse benutzt werden. Überall dort, wo ein Objekt der Oberklasse erwartet wird, kann auch ein Objekt der Unterklasse benutzt werden.
Beispiel:
In der folgenden Klassen wird ein Objekt des Typs Buch und ein Objekt des Typs UebersetzesBuch erzeugt. Auf beiden werden einige Eigenschaften getestet.
BenutzeUebersetztesBuch
class BenutzeUebersetztesBuch{
  public static void main(String [] _){
    Buch b1 = new Buch("Zettels Traum",150,"Arno Schmidt");
    UebersetztesBuch b2 
     = new UebersetztesBuch
              ("Eines Tages ich sprechen hübsch"
              ,19,"Sedaris","Harry Rowolth","Englisch");
    
    System.out.println(b1.toString());
    System.out.println(b2.toString());

    b2.erhöhePreisUmProzent(8);
    System.out.println(b2.toString());

    System.out.println
    ("Der Übersetzer von: "+b2.titel+" ist: "+b2.übersetzer);
  }  
}

Aufgabe 15   Schreiben Sie eine Testklasse, in der Objekte des Typs Student getestet werden.

Appendix A
Beispielaufgaben

Aufgabe 0  
Die folgenden Dokumente sind kein wohlgeformetes XML. Begründen Sie, wo der Fehler liegt, und wie dieser Fehler behoben werden kann.
Aufgabe 1   Was geben die folgenden Javaprogramme auf dem Bildschirm aus, wenn sie ausgeführt werden:
Aufgabe 2   Schreiben Sie das folgende Programm so um, daß es statt einer for-Schleife eine while-Schleife benutzt.
class Aufgabe3 {

  static public int hochN(int i, int exp){
    int result = 1;

    for (int j=0; j < exp;j=j+1){
      result = result*i;
    }

    return result;
  }

}

Aufgabe 3  
Ergänzen Sie das untere Programm, indem Sie den fehlenden Programmtext der Methode m gemäß der im Kommentar gegebenen Spezifikation einfügen.
class Aufgabe4 {
  static int m(int x){
     //m berechnet das vierfache des Eigabeparameters x.
  }

}

Aufgabe 4  
Gegeben sind das folgende XML-Dokument:
<?xml version="1.0" encoding="iso-8859-1" ?>
<?xml-stylesheet type="text/xsl" href="person.xsl"?>
<person>
  <name>Shakespeare</name>
  <vorname>William</vorname>
</person>

und das darin referenzierte XSL Stylesheet person.xsl:
<xsl:stylesheet version="1.0"
             xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
     <html><head><title>Person</title></head>
       <body><xsl:apply-templates/></body>
     </html>
  </xsl:template>

  <xsl:template match="name">
     <b><xsl:apply-templates/></b><br/>
  </xsl:template>

  <xsl:template match="vorname">
     <em><xsl:apply-templates/></em>
  </xsl:template>
</xsl:stylesheet>

Wie sieht der durch den XSLT-Prozessor aus diesen zwei Dateien generierte HTML-Code aus.
Aufgabe 5   Sie sollen ein Javaapplet schreiben, das auf einer Webseite eingebunden ist. Immer, wenn jemand die Seite von der Website auf seinem lokalen Rechner betrachtet, soll das Applet auf dem lokalen Rechner eine Datei anlegen, in der Datum und Uhrzeit für die Aktivierung des Applets geschrieben wird.
Warum können Sie ein solches Applet nicht realisieren?

Appendix B
Gesammelte Aufgaben

Aufgabe 0   Schreiben Sie das obige Programm mit einen Texteditor ihrer Wahl. Speichern Sie es als Hallo.java ab. Übersetzen Sie es mit dem Java-Übersetzer javac. Es entsteht eine Datei hallo.class. Führen Sie das Programm mit dem Javainterpreter java aus.
Aufgabe 1   Übersetzen Sie das Programm Minimal aus dem letzem Abschnitt und versuchen Sie dieses Programm laufen zu lassen. Was für eine Fehlermeldung bekommen Sie?
Aufgabe 2   Testen Sie, was passiert, wenn Sie im obigen Programm die Methode druckeDoppelt ohne konkreten Wert für den Parameter aufrufen.
Aufgabe 3   Schreiben Sie eine zusätzliche Methode in obiger Klasse. Die Methode soll zwei Zahlen x und y als Parameter haben und als Ergebnis 2*x+4*y berechnen.
Aufgabe 4   Schreiben Sie eine Methode, die für eine ganze Zahl die Fakultät dieser Zahl berechnet. Testen Sie die Methode zunächst mit kleinen Zahlen, anschließend mit großen Zahlen. Was stellen Sie fest.
Aufgabe 5   Schreiben Sie ein XML Dokument, daß nach den Regeln der obigen DTD gebildet wird.
Aufgabe 6   Schreiben Sie eine Klasse Person1, die eine Person modelliert. eine Person soll einen Namen, einen Vornamen, eine Straße, eine Hausnummer, eine Postleitzahl und einen Ort als Daten enthalten.
Aufgabe 7   Schreiben Sie eine Klasse Person2, die zusätzlich zu den Feldern aus ihrer Klasse Person1 noch einen Konstruktor enthält, der die Felder der Klasse mit als Argumente übergebenen Daten füllt.
Aufgabe 8   Erzeugen Sie in einer Testklasse zwei Objekte des Typs Person2.
Aufgabe 9   Schreiben Sie ein kleines Testprogramm, daß Ihre Klasse Person2 benutzt. Erzeugen Sie zwei Objekte des Typs Person2. Geben Sie einige der Daten dieser Objekte auf dem Bildschirm aus. Ändern Sie dann die Adresse einer der Personen und geben Sie die neuen Daten dieser Person auf dem Bildschirm aus.
Aufgabe 10   Schreiben Sie eine Klasse Person, indem Sie Ihre Klasse Person2 um zwei Methoden erweitern.
Aufgabe 11   Schreiben Sie eine Testklasse für Ihre Klasse Person, so daß Sie die Methoden der Klasse Person alle einmal aufgerufen haben.
Aufgabe 12   Schreiben Sie ein kleines Testprogramm, das Objekte des Typs Buchausleihe erzeugt und Methoden darauf anwendet.
Aufgabe 13   Suchen Sie sich aus der Javadokumentation zur Klasse String weitere Methoden heraus und schreiben Sie ein Testprogramm, daß diese Methoden ausprobiert.
Aufgabe 14   Schreiben Sie eine Klasse Student, die die Klasse Person um ein weiteres Feld matrikelNr erweitert.
Aufgabe 15   Schreiben Sie eine Testklasse, in der Objekte des Typs Student getestet werden.

Index

Verzeichnis der Klassen

Footnotes:

1Mehr oder weniger ist dieses sogar bei Spielekonsolen der Fall und umgekehrt ist es Tüftlern gelungen auf Spielekonsolen auch komplette Betriebssysteme zu installieren.
2Es ist wohl offiziell nie bekannt gegeben worden, wofür das NT im Namen steht. Es wird vermutet, daß der Name abgekürzt WNT sich aus VMS ableitet, indem für jeden Buchstaben von VMS der nächsthöhere Buchstabe des Alphabets gewählt wurde. Der Chefentwickler von Windows NT war vorher Entwickler des Betriebssystems VMS. Ähnlich soll der Computer HAL in dem Film 2001 aus den Buchstaben IBM abgelitten worden sein.
3Spötter und Liebhaber sprechen gern von OS-Halbe.
4Was der Endbenutzer beim Apple nie zu sehen bekommt.
5Apple kennt diese Namenserweiterung traditionell nicht. Dort gibt es eine interne Speicherung über die Art der Datei.
6Zumindest nicht für den Endanwender. Anwendungsentwicklern standen durchaus Werkzeuge mit einer Kommandozeile zur Verfügung.
7I18N ist eine Abkürzung für das Wort internationalization, das mit einem i beginnt, mit einem n endet und dazwischen 18 Buchstaben hat.
8Dieses gilt für die meisten Programmiersprachen.
9Sofern ein Alphabet benutzt wird, daß die Unterscheidung von Groß- und Kleinschreibung kennt.
10und fast allen anderen Programmiersprachen
11Wahr oder falsch, eine dritte Möglikchkeit gibt es nicht. Logiker postulieren dieses als tertium non datur.
12Konstrukte mit Operatoren nennt man dagegen Ausdrücke.
13Der Javaübersetzer macht kleine Prüfungen auf konstanten Werten, ob Schleifen jeweils durchlaufen werden oder nicht terminieren. Deshalb brauchen wir die Hilfsmethode falsch().
14Man sagt, ein Pilot brauche den Copiloten, damit dieser die Handbücher für das Flugzeug trägt.
15WYSIWYG steht für what you see is what you get und drückt aus, daß bereits im Editor beim Edieren das fertige Dokument in seiner eigentlichen Darstellungsform zu sehen ist.



File translated from TEX by TTH, version 3.20.
On 20 Jun 2003, 17:30.