Galileo Computing < openbook >
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Java ist auch eine Insel (2. Aufl.) von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 1.4
Java ist auch eine Insel (2. Auflage)
gp Kapitel 2 Sprachbeschreibung
  gp 2.1 Anweisungen und Programme
  gp 2.2 Programme
    gp 2.2.1 Kommentare
    gp 2.2.2 Funktionsaufrufe als Anweisungen
    gp 2.2.3 Die leere Anweisung
    gp 2.2.4 Der Block
  gp 2.3 Elemente einer Programmiersprache
    gp 2.3.1 Textkodierung durch Unicode-Zeichen
    gp 2.3.2 Unicode-Tabellen unter Windows
    gp 2.3.3 Bezeichner
    gp 2.3.4 Reservierte Schlüsselwörter
    gp 2.3.5 Token
    gp 2.3.6 Semantik
  gp 2.4 Datentypen
    gp 2.4.1 Primitive Datentypen
    gp 2.4.2 Wahrheitswerte
    gp 2.4.3 Variablendeklarationen
    gp 2.4.4 Ganzzahlige Datentypen
    gp 2.4.5 Die Fließkommazahlen
    gp 2.4.6 Zeichen
    gp 2.4.7 Die Typanpassung (das Casting)
    gp 2.4.8 Lokale Variablen, Blöcke und Sichtbarkeit
    gp 2.4.9 Initialisierung von lokalen Variablen
  gp 2.5 Ausdrücke
    gp 2.5.1 Zuweisungsoperator und Verbundoperator
    gp 2.5.2 Präfix- oder Postfix-Inkrement und -Dekrement
    gp 2.5.3 Unäres Minus und Plus
    gp 2.5.4 Arithmetische Operatoren
    gp 2.5.5 Die relationalen Operatoren
    gp 2.5.6 Logische Operatoren
    gp 2.5.7 Reihenfolge und Rang der Operatoren in der Auswertungsreihenfolge
    gp 2.5.8 Was C(++)-Programmierer vermissen könnten
  gp 2.6 Bedingte Anweisungen oder Fallunterscheidungen
    gp 2.6.1 Die if-Anweisung
    gp 2.6.2 Die Alternative wählen mit einer if/else-Anweisung
    gp 2.6.3 Die switch-Anweisung bietet die Alternative
  gp 2.7 Schleifen
    gp 2.7.1 Die while-Schleife
    gp 2.7.2 Schleifenbedingungen und Vergleiche mit ==
    gp 2.7.3 Die do/while-Schleife
    gp 2.7.4 Die for-Schleife
    gp 2.7.5 Ausbruch planen mit break und Wiedereinstieg mit continue
    gp 2.7.6 break und continue mit Sprungmarken
  gp 2.8 Methoden einer Klasse
    gp 2.8.1 Bestandteil einer Funktion
    gp 2.8.2 Aufruf
    gp 2.8.3 Methoden ohne Parameter
    gp 2.8.4 Statische Methoden (Klassenmethoden)
    gp 2.8.5 Parameter und Wertübergabe
    gp 2.8.6 Methoden vorzeitig mit return beenden
    gp 2.8.7 Nicht erreichbarer Quellcode bei Funktionen
    gp 2.8.8 Rückgabewerte
    gp 2.8.9 Methoden überladen
    gp 2.8.10 Vorinitialisierte Parameter bei Funktionen
    gp 2.8.11 Finale lokale Variablen
    gp 2.8.12 Finale Referenzen in Objekten und das fehlende const
    gp 2.8.13 Rekursive Funktionen
    gp 2.8.14 Die Ackermann-Funktion
    gp 2.8.15 Die Türme von Hanoi
  gp 2.9 Weitere Operatoren
    gp 2.9.1 Bitoperationen
    gp 2.9.2 Vorzeichenlose Bytes in ein Integer und Char konvertieren
    gp 2.9.3 Variablen mit Xor vertauschen
    gp 2.9.4 Die Verschiebeoperatoren
    gp 2.9.5 Setzen, Löschen, Umdrehen und Testen von Bits
    gp 2.9.6 Der Bedingungsoperator
    gp 2.9.7 Überladenes Plus für Strings
  gp 2.10 Einfache Benutzereingaben


Galileo Computing

2.2 Programme  downtop

Programme setzen sich aus Anweisungen zusammen. In Java können jedoch nicht einfach Anweisungen in eine Datei geschrieben und dem Compiler übergeben werden. Sie müssen zunächst in einen Rahmen gepackt werden. Dieser Rahmen definiert die Hauptklasse und eine Funktion.

Auch wenn die folgenden Programmcodezeilen am Anfang etwas befremdend wirken, wir werden sie zu einem späteren Zeitpunkt noch genauer erklären. Wir geben der folgenden Datei den Namen Main.java.

Listing 2.1   Main.java

class Main
{
  public static void main( String args[] )
  {
  // Hier ist der Anfang unserer Programme

  // Jetzt ist hier Platz für unsere eigenen Anweisungen

  // Hier enden unsere Programme
  }
}

Ein Java-Programm muss immer in einer Klasse definiert sein. Wir haben sie Main genannt, der Name ist jedoch beliebig. In geschweiften Klammern folgen benutzerdefinierte Methoden, also Funktionen, die die Klasse anbietet. Eine Funktion ist eine Sammlung von Anweisungen unter einem Namen. Mathematische Funktionen sind mit Funktionen aus Programmiersprachen vergleichbar. Eine Sinus-Funktion schafft es beispielsweise zu einem gegebenen Wert den Sinus zu berechnen. Wir wissen zwar nicht, wie die Funktion das macht, aber sie kann es. Der Begriff »Funktion« und der objektorientierte Name »Methode« sind in diesem Tutorial synonym verwendet. Vor einer Methode stehen unterschiedliche Modifizierer. Der Modifizierer static sagt, dass die Methode auch ohne Objekt benutzt werden kann. Wir werden in den folgenden Kapiteln nur mit statischen Methoden arbeiten.

Wir programmieren hier eine besondere Funktion, die sich main() nennt. Die Schlüsselwörter davor und die Angabe in dem Paar runder Klammern hinter dem Namen müssen wir einhalten. Die Funktion main() ist für die Laufzeitumgebung etwas ganz Besonderes, denn beim Aufruf des Java-Interpreters mit einem Klassennamen wird unsere Funktion als Erstes ausgeführt. Demnach werden genau die Anweisungen ausgeführt, die innerhalb der geschweiften Klammern stehen. Halten wir uns fälschlicherweise nicht an die Syntax für den Startpunkt, so kann der Interpreter die Ausführung nicht beginnen und wir haben einen semantischen Fehler gemacht, obwohl die Funktion selbst korrekt gebildet ist. Innerhalb von main() befindet sich der Name args, mit dem die Parameter angesprochen werden. Der Name ist willkürlich, wir werden allerdings immer args verwenden.

Hinter den beiden Geteilt-Zeichen // befinden sich Kommentare. Sie gelten bis zum Ende der Zeile und dienen dazu, Erläuterungen zu den Quellcodezeilen hinzuzufügen, die ihn verständlicher machen.

Programme übersetzen und starten

Der Quellcode eines Java-Programms ist so allein nicht ausführbar. Ein spezielles Programm, der Compiler (auch Übersetzer genannt), transformiert das geschriebene Programm in eine andere Repräsentation. Ein Quellcode mit Anweisungen für Programme muss aber nicht zwingend übersetzt werden. Eine andere Gattung für ein Ablaufmodell ist der Interpreter. Er liest die Datei Schritt für Schritt ein und führt dann die Anweisungen aus. Der Compiler liest die Datei in einem Rutsch und meldet Fehler. Häufig werden Skriptsprachen interpretiert, früher waren es oft BASIC-Programme. Compiler für geläufige Programmiersprachen wie C(++) oder Delphi übersetzen den Quellcode in Maschinencode. Das ist Binärcode, der vom Prozessor im Computer direkt ausführbar ist. Da unterschiedliche Rechner aber unterschiedliche Prozessoren besitzen, sind die Programme nicht direkt auf verschiedenen Rechnerplattformen ausführbar. Java ist jedoch als Programmiersprache entworfen worden, die plattformunabhängig ist, sich also nicht an einen physikalischen Prozessor klammert. Der Compiler übersetzt den Quellcode nicht in Binärcode für einen konkreten Prozessor, sondern in einen plattformunabhängigen Code, den Bytecode. Prozessoren wie Intel-, AMD- oder G5-CPU können aber mit diesem Bytecode nichts anfangen. Hier hilft ein Interpreter weiter. Dieser liest Anweisung für Anweisung aus dem Bytecode und führt entsprechende Befehle auf dem Mikroprozessor aus. Daher ist Java eine kompilierte und interpretierte Sprache zugleich.

Zum Übersetzen der Programme bietet Sun im JDK den Compiler javac an. Der Interpreter heißt java. Wir haben im einführenden Kapitel über den Ablauf und die möglichen Fehler schon gesprochen.

Beispiel   Das Programm mit dem Namen Main.java übersetzen und starten:
$ javac Main.java
$ java  Main

Befindet sich im Quellcode nur die kleinste Ungenauigkeit, die der Compiler nicht toleriert, gibt er einen Fehler aus. Erst wenn Bytecode erzeugt wurde, kann der Interpreter diesen ausführen. Leider sehen wir noch nichts, da wir keine Anweisung gegeben haben. Dies soll sich nun ändern, denn wir wollen lernen, wie eine Bildschirmausgabe aussieht.


Galileo Computing

2.2.1 Kommentare  downtop

Programmieren heißt nicht nur, einen korrekten Algorithmus in einer Sprache auszudrücken, sondern auch, unsere Gedanken verständlich zu formulieren. Dies geschieht beispielsweise durch eine sinnvolle Namensgebung für Programmobjekte wie Klassen, Funktionen und Variablen. Ein selbsterklärender Klassenname hilft den Entwicklern erheblich. Doch die Lösungsidee und der Algorithmus wird auch durch die schönsten Variablennamen nicht zwingend klarer. Damit Außenstehende (und wir nach Monaten selbst) unsere Lösungsidee schnell nachvollziehen und später das Programm erweitern oder abändern können, werden Kommentare in den Quelltext eingeführt. Sie dienen nur den Lesern der Programme, haben aber auf die Abarbeitung keine Auswirkungen.

Kommentarblöcke können durch /* und */ abgetrennt werden. Zwischen diesen Zeichen kann nahezu jeder beliebige Text stehen. Da es keinen Präprozessor gibt, ist es Aufgabe des Compilers, die Bemerkungen aus dem Quelltext zu entfernen. Da im Einzelfall nur Zeilen auskommentiert werden sollen, ist in Java auch das in C++ verwendete // erlaubt, welches wir schon kennen gelernt haben.

// Zeilenkommentar

/*
 * Blockkommentar
 */

Dokumentationskommentare

Neben dem Blockkommentar bietet Java eine interessante Möglichkeit der Programmdokumentation. Die Zeichen /** und */ beschreiben einen so genannten Dokumentationskommentar (engl. Doc-Comment), welcher vor Methoden- oder Klassendefinitionen angewendet wird.

Beispiel   Dokumentationskommentar:
/**
 * Hier drinnen ist ein Doc-Kommentar
 */

Der Teil zwischen den Kommentaren wird mit einem externen Dienstprogramm in HTML- oder Framemaker-Dokumente umgewandelt.

Blockkommentare dürfen nicht geschachtelt sein. Ein Zeilenkommentar darf aber im Blockkommentar enthalten sein.


Galileo Computing

2.2.2 Funktionsaufrufe als Anweisungen  downtop

Bisher kennen wir keine konkreten Anweisungen. Daher möchte ich jetzt eine einfache Anweisung vorstellen, die wichtig für Programme ist: der Funktionsaufruf. Allgemein hat er folgendes Format:

funktionsname();

Innerhalb der Klammern dürfen wir Parameter angeben. Es lassen sich auch Funktionen in dieser Form anwenden, die ein Ausdruck sind und ein Ergebnis zurückgeben, beispielsweise eine Sinus-Funktion. Der Rückgabewert wird dann verworfen. Im Fall der Sinus-Funktion macht das wenig Sinn, denn sie macht außer der Berechnung nichts anderes.

Wir interessieren uns für eine Funktion, die eine Zeichenkette auf dem Bildschirm ausgibt. Sie heißt println(). Die meisten Methoden verraten durch ihren Namen, was sie leisten, und für eigene Programme ist es sinnvoll, aussagekräftige Namen zu verwenden. Wenn die Java-Entwickler die Methode glubschi() genannt hätten, würde uns der Sinn der Methode verborgen bleiben. println() zeigt jedoch durch den Wortstamm »print« an, dass etwas geschrieben wird. Die Endung ln (kurz für line) bedeutet, dass noch ein Zeilenvorschubzeichen ausgegeben wird. Umgangssprachlich heißt das: Eine neue Ausgabe beginnt in der nächsten Zeile. Neben println() existiert die Bibliotheksfunktion print(), die keinen Zeilenvorschub hervorruft.

Die printXXX()-Methoden können in Klammern unterschiedliche Parameter bekommen. Ein Parameter ist ein Wert, den wir der Funktion beim Aufruf mitgeben wollen. Wir wollen die Diskussion über Parameter aber noch etwas verschieben. Unser printXXX()-Aufruf soll lediglich Zeichenketten ausgeben. (Ein anderes Wort für Zeichenketten ist String.) Ein String ist eine Folge von Buchstaben, Ziffern und Sonderzeichen in doppelten Anführungszeichen:

"Ich bin ein String"
"Ich auch. Und ich koste 7.59 _"

Um die obere Ausgabe mit dem Funktionsaufruf und einem trennenden Zeilenvorschub auf den Bildschirm zu bekommen, schreiben wir:

System.out.println( "Ich bin ein String" );
System.out.println();                // Gibt eine Leerzeile aus
System.out.println( "Ich auch. Und ich koste 7.59 _" );

Auch wenn eine Funktion keine Parameter erwartet, muss beim Aufruf hinter dem Funktionsnamen ein Klammerpaar folgen. Dies ist konsequent, da wir so wissen, dass es ein Funktionsaufruf ist und nichts anderes. Andernfalls führt es zu Verwechslungen mit Variablen.

Eine weitere Eigenschaft von Java wird ebenfalls an dem Funktionsaufruf sichtbar. Es gibt Methoden, die unterschiedliche Parameter (eine andere Anzahl oder einen unterschiedlichen Typ) besitzen, aber gleichen Namen tragen. Diese Funktionen nennen wir überladen. Die printXXX()-Methoden sind sogar vielfach überladen und akzeptieren neben Strings auch weitere Werte als Parameter.

Programmieren wir eine ganze Java-Klasse, die etwas auf dem Bildschirm ausgibt.

Listing 2.2   Main.java

class Main
{
  public static void main( String args[] )
  {
  // Hier ist der Anfang unserer Programme

    System.out.println( "Hallo Javanesen" );

  // Hier enden unsere Programme
  }
}
Hinweis     Anweisungen wie ein Funktionsaufruf enden immer mit einem Semikolon.

Erste Idee der Objektorientierung

In einer objektorientierten Programmiersprache sind alle Methoden an bestimmte Objekte gebunden (daher der Begriff objektorientiert). Betrachten wir zum Beispiel das Objekt Radio. Ein Radio spielt Musik ab, wenn der Ein-Schalter betätigt wird und ein Sender und die Lautstärke eingestellt sind. Ein Radio bietet also bestimmte Dienste (Operationen) an, wie Musik an/aus, lauter/leiser. Zusätzlich hat ein Objekt auch noch einen Zustand. Es ist zum Beispiel die Farbe oder das Baujahr. Wichtig in objektorientierten Sprachen ist, dass die Operationen und Zustände immer (und da gibt es keine Ausnahmen) an Objekte beziehungsweise Klassen gebunden sind (mehr zu dieser Unterscheidung später). Der Aufruf einer Methode auf ein Objekt richtet die Anfrage genau an ein bestimmtes Objekt. Steht in einem Java-Programm einfach nur die Anweisung lauter, so weiß der Compiler nicht, wen er fragen soll. Was ist, wenn es auch noch einen Fernseher gibt? Aus diesem Grunde verbinden wir das Objekt, das etwas kann, mit der Operation. Ein Punkt trennt das Objekt von der Operation oder dem Zustand.

So gehört auch println() zu einem Objekt, welches die Bildschirmausgabe übernimmt. Dass eine Methode immer zu einem Objekt gehört, können wir auch an unserem eigenen Programm überprüfen. main() gehört zu der Klasse Main, die später ein Objekt bilden kann. Daher können wir in Java auch nicht einfach die Ausgabeanweisung schreiben. println() gehört zu einem Objekt mit dem Namen out. Dieses Objekt ist wiederum Teil der Klasse System. Wir können das vergleichen mit einem Aufruf zum Beispiel von

BRD.aktuellerBundeskanzler.fragen( "Wieso kassieren ARD" +
 " und ZDF jährlich 11 Mrd. Mark Rundfunkgebühren"+
 " und müssen davon nichts abführen?" );

Mehr zu diesen Aufrufen zu einem späterem Zeitpunkt. Das obige Beispiel macht aber jetzt schon deutlich, dass Strings mit dem Plus zusammengehängt werden können.


Galileo Computing

2.2.3 Die leere Anweisung  downtop

Die einfachste Anweisung besteht nur aus einem Semikolon und ist die leere Anweisung:

;

Sie wird verwendet, wenn die Sprachgrammatik eine Anweisung vorschreibt, aber in dem Programmablauf keine Anweisung vorkommen muss. So muss etwa hinter dem Schleifenkopf eine Anweisung folgen. Wir werden bei den Schleifen eine Anwendung der leeren Anweisung sehen.


Galileo Computing

2.2.4 Der Block  toptop

Ein Block innerhalb von Methoden oder statistischen Blöcken fasst eine Gruppe von Anweisungen zusammen, die hintereinander ausgeführt werden. Dazu werden die Anweisungen zwischen geschweiften Klammern geschrieben:

{
  Anweisung1;
  Anweisung2;
  ...
}

Ein Block kann überall dort verwendet werden, wo auch eine einzelne Anweisung stehen kann. Der neue Block hat jedoch eine Besonderheit für Variablen, denn er bildet einen lokalen Bereich für die darin befindlichen Anweisungen inklusive der Variablen. Blöcke können auch geschachtelt werden.






1   Na ja, so ganz präzise ist das auch nicht. In einem static-Block könnten wir auch einen Funktionsaufruf reinsetzen, doch das wollen wir hier einmal nicht annehmen. static-Blöcke werden beim Laden der Klassen in die virtuelle Maschine ausgeführt. Andere Initialisierungen sind dann auch schon gemacht.

2   In C++ haben die Entwickler übrigens das aus der Vor-Vorgängersprache BCPL wieder eingeführt, was in C entfernt wurde.

3   Bei uns am Niederrhein steht glubschi für etwas Glitschiges, Schleimiges.

4   Abkürzung für Methoden, die mit print- beginnen, also print() und println().





Copyright © Galileo Press GmbH 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de