Einführung in Java am GZG

Wichtige Sprachelemente von Java

Die wesentlichen Sprachelemente von Java werden hier - vor allem zum Nachschlagen - kurz zusammengestellt:

(Verantwortlich für die Seiten: W. Seyboldt  / Stand: 11. Mai 2006)


Allgemeine Bemerkungen

Informationen zur Geschichte, siehe hier

Java gilt als "einfache objektorientierte Sprache", d.h. sie besteht aus wenigen aber komprimiert geschriebenen Struktur-Elementen, mit denen objektorientierte Programme geschrieben werden. Sie ähnelt in vielem den Sprachen C und C++, hat aber die für ein objektorientiertes Vorgehen problematischen Konstrukte nicht (Java hat z.B. keine expliziten Pointer, obwohl natürlich alle Objekt-Variablen implizit Pointer sind). Im Internet finden sich viele Beschreibungen von Java. Es finden sich auch viele mehr oder weniger tiefschürfende philosophischen Abhandlungen über objektorientierte Programmierung und deren Vorgängervarianten wie strukturierte und modulare Programmierung (siehe Literaturverzeichnis). 

Bezeichner (Variablen-, Methoden und Klassennamen):
Java unterscheidet zwischen Groß- und Kleinbuchstaben. Mit eins, Eins, eiNs und EINS können also vier verschiedene Dinge bezeichnet werden. 
Es gilt folgende Konvention, die im Unterricht am GZG strikt einzuhalten ist: Alle Klassennamen (und Filenamen, die gleich lauten wie die in ihnen programmierten Klassen) beginnen mit Großbuchstaben, alle übrigen Objekte beginnen mit Kleinbuchstaben. Komplexere Bezeichner, die aus mehreren Worten bestehen, werden zusammengeschrieben, wobei allerdings der erste Buchstaben eines neuen Worts im Bezeichner (d.h. im Namen der Variablen oder der Methoden) stets groß geschrieben wird. Konstanten, d.h. Daten, die nicht verändert werden können, und die in Java mit dem Qualifizierer final deklariert werden, werden wie in C nur mit Großbuchstaben bezeichnet´.
  • Alle Klassen beginnen mit Großbuchstaben.
  • Alle Objekte, Daten und Methoden beginnen mit Kleinbuchstaben.
  • Besteht ein Strukturname aus mehr als einem Wort, so werden diese Worte ohne Leerzeichen oder Unterstrich zusammengeschrieben. Die ersten Buchstaben der Folgeworte sind groß, die restlichen klein (etwa dasIstEinBeispiel). 
  • In Java muss eine Klasse in einem File abgespeichert werden, das denselben Namen wie die Klasse hat.
  • Sämtliche Files, die zu einem Projekt gehören, stehen möglichst in einem gemeinsamen Ordner, der oft denselben Namen hat wie die Klasse.
Filenamen:
Jedes eigenständige Java-Programm und jedes Applet sollte in einem eigenen Ordner stehen. Der Klassenname und der Filename, in dem sich die Hauptklasse befindet, müssen übereinstimmen. Java erwartet dies auf alle Fälle. Beispiel: Das File, das die Klasse BspApplet enthält, heißt BspApplet.java. Oft steht dieses File zusätzlich in einem Ordner namens BspApplet - in diesem Ordner sollte auch ein evtl. nötiges HTML-File namens BspApplet.html stehen, das das Applet aufruft (Bem.: Dieses HTML-File wird von JCreator automatisch beim Erstellen eines Applet-Templates generiert, siehe hier). Der vom Javacompiler erzeugte Bytecode steht im File BspApplet.class.
Kommentar:
Die beiden Zeichen // bedeuten, dass ab hier bis zum Rest der Zeile alles Kommentar ist, d.h. vom Compiler zu überlesen ist, da dieser Text sich an den Menschen wendet.
Alle Zeichen zwischen /* und */ sind ebenfalls Kommentar. Dieser Kommentar darf sich auch auf die folgenden Zeilen ausdehnen.
Alle Zeichen zwischen /** und */ sind Doc-Comment. D.h. sie können von dem Tool javadoc ausgewertet werden, um eine automatische Dokumentation zu erstellen (falls in diesem Bereich des Quellcodes eine sinnvolle Beschreibung erstellt wurde). Auf der javadoc Home Page finden sich hierzu nähere Informationen.
Anweisungen und Blöcke
Eine einfache Anweisung besteht aus dem Aufruf einer Methode oder aus einer Zuweisung. Jede Anweisung endet mit einem Semikolon (;). Fehlt dieses, so gibt der Compiler meistens für die folgende Zeile eine Fehlermeldung aus, die oft unverständlich erscheint - überprüfe bei unverständlichen Fehlermeldungen deshalb immer, ob ein Semikolon fehlt oder eine geschweifte Klammer nicht geschlossen wurde.
Ein Spezialfall einer einfachen Anweisung ist die leere Anweisung, die nur aus einem Semikolon besteht. Dies kann z.B. bei for-Schleifen sinnvoll sein.
Mitunter müssen mehrere Anweisungen als Einheit aufgefasst werden. Dies geschieht dadurch, dass die Anweisungen in geschweifte Klammern eingeschlossen werden. Die geschweifte Klammern und die Anweisungen werden dann als Block bezeichnet und syntaktisch wie eine einzige Anweisung behandelt.. Nach der schließenden Klammer eines Blocks muss kein Semikolon stehen.
Weitere wichtige Anweisungen sind Schleifen und bedingte Anweisungen.
Wenn man nur von einer Anweisung redet, meint man damit also entweder eine einfache Anweisung, einen Block, eine bedingte Anweisung oder eine Schleife. 
Beispiele:
        g.drawString("GZG", 10, 20);
        i = r+7;
        ;
        while ... {
           i++;
           j=i*3;
        }     
        for (int i = 0; i<28; i++) {...}
        if ((a%2==0) {a=a/2;}

Java ist von Grund auf objektorientiert. Java besteht nur aus wenigen Sprachelementen, d.h. die eigentliche Sprache ist auf das Wesentliche konzentriert. Die Sprachkonstrukte sind die der Sprache C. Damit kann jeder, der Java-Programme lesen kann, auch relativ einfach C-Programme lesen und umgekehrt. Wichtige und grundlegende Klassen und Algorithmen von Java (wie auch von C) werden in sogenannten Klassen-Bibliotheken bereitgestellt, die Bestandteil des Compilers sind. Jeder Programmierer muss außer den Sprachkonstrukten lernen, auf welche Funktionen, auf welche Klassen, er zurückgreifen kann und muss. Es gilt aber nicht nur diese Namen zu lernen, sondern auch die zugehörigen Vorgehensweisen der Informatik.

Alle Programmierarten kennen folgende Grundbegriffe, die im Wesentlichen von der Hardware des Computers bedingt sind, bzw. mit ihr korrespondieren: Variable (Speicherplätze), Zuweisungen, Ein- und Ausgabe, Schleifen (Wiederholungen), Bedingungen (if-Anweisungen), Berechnungen und Algorithmen, Graphiken, Windows (oder Frames in der Terminologie von Java - Panels sind eine Vorstufe von Frames, die lediglich aus einem strukturlosen Bereich des Bildschirms bestehen). 

 

Variablen und Objektdeklarationen

Deklarationen und Initialisierungen

Eine Variable ist in Java wie in allen Programmiersprachen ein Teil des Hauptspeichers, der zur Erleichterung im Quellfile mit einem Namen (anstatt mit einer Speicheradresse) referenziert werden kann. Der Name, der Bezeichner der Variablen, sollte in Java mit einem kleinen Buchstaben beginnen und eine sinnvolle Beschreibung des Speicherinhaltes sein. Jede Variable (und jedes Objekt) muss deklariert werden, d.h. dem Compiler muss mitgeteilt werden, wie die Variable (oder das Objekt) heißt, wie viele Bits der Speicherplatz benötigt und wie diese Bits zu interpretieren sind. Die letzten beiden Informationen werden durch den Typ der Variablen angegeben - oder die Klasse, wenn die Variable ein Objekt ist. Der Typ (die Klasse) steht stets vor dem Bezeichner - wie in C, umgekehrt wie in Delphi oder Pascal. Nach dem Bezeichner kann sich eine Initialisierung anschließen, was meist sinnvoll ist. In einem Speicherplatz sollte ja immer ein bestimmter Wert stehen. (siehe Beispiele)

Einfache Datenstrukturen für Zahlen sind: int, long, float und double (siehe). 

Die Datenstruktur vom Typ int besteht in Java aus einem Speicherbereich von 4 Byte = 32 Bit, die von long aus 64 Bit. Die Bits dieser Speicherplätze werden als Zahlen im Zweiersystem interpretiert, wobei das höchstwertige Bit entscheidet, ob eine Zahl negativ oder positiv ist. Besteht der Speicherplatz beispielsweise aus 32 Bits, also aus Bit 0 bis Bit 31, und Bit 0, Bit 4 und Bit 7 sind gesetzt, so wird dieser Zustand als Zahl i = 1 +  1*2^4 + 1*2^7 = 1 + 16 + 128 = 145 interpretiert. Da dass höchstwertige Bit, hier Bit 31, Null ist, ist die Zahl positiv. Ist das höchstwertige Bit gesetzt, so werden zuerst alle Bits gedreht, d.h. jedes gesetzte Bit wird gelöscht und umgekehrt. Dann wird die Zahl nach obigem Schema bestimmt und mit einem Minus versehen (Stichwort Zweierkomplement). Eine Variable vom Typ int kann damit Werte zwischen –231 und +231-1 annehmen. 

Eine Variable vom Typ float bzw. double ist eine Dezimalzahl, die durch eine Mantisse und einen Exponenten beschreiben wird. Eine Variable vom Typ float belegt in Java 32 Bit, eine vom Typ double 64 Bit. Die Genauigkeit der Mantisse im Fall double, dem Standard-Typ für Dezimalzahlen bei Java, beträgt etwa 18 Stellen, der Exponent kann Werte von -324 bis +308 annehmen. Eine Variable vom Typ float hat 9 richtige Stellen und der Exponent kann Werte von -45 bis +38 annehmen.

Variablen und Objekte können überall in einem Programm deklariert werden - auch in Schleifen, was oft sehr sinnvoll ist. Variablen kann mit einem Gleichheitszeichen und einer Zahl sofort ein Wert zugeordnet werden. Diese Zahl wird dann in den entsprechenden Speicherbereich geschrieben. Die Speicherplätze der Objekte sind hingegen Zeiger (Pointer) auf die eigentlichen Objekte, d.h. es sind Adressen auf große Speicherbereiche, die bei der Deklaration noch nicht reserviert werden. Das Objekt wird erst bei der Initialisierung mit dem Stichwort new erzeugt. Nach dem Stichwort new folgt der sogenannte Konstruktor, eine Methode, die gleich heißt, wie die Klasse, die während der Erzeugung des Objekts sofort ausgeführt wird und die nötigen Initialisierungen vornimmt.  

Alle Daten werden in Java automatisch initialisiert: Zahlen werden mit 0, Boolesche Variablen mit false vorbelegt. Außerdem versucht der Java-Compiler nicht initialisierte Zahlen und Objekte zu erkennen. 

 

Einfache Datentypen

Typ Inhalt Standard Größe Min- und Max-Wert
boolean true / false false 1 Bit -
byte Integer mit Vorzeichen 0 8 Bit -128 .. 127
short Integer mit Vorzeichen 0 16 Bit -32768 .. 32767
int Integer mit Vorzeichen 0 32 Bit -2 147 483 648 .. 2 147 483 647
long Integer mit Vorzeichen 0 64 Bit -2^63 ... 2^63-1 (18 Ziffern)
float Fließkommazahl nach IEEE-754 0.0 32 Bit ±1.40239846E-45 .. ±3.40282347E38
double Fließkommazahl nach IEEE-754 0.0 64 Bit ±4.9..E324 .. ±1.79E308 (18 Stellen)
char Unicode-Zeichen \u0000 16 Bit \u0000 .. \uFFFF

Weitere Informationen finden sich etwa in Guido Krügers On-Line-Version von Goto Java 2, Kapitel 4 (JK07), oder in den Büchern B845, S.60 und B863, S.25 und S.237)

Beispiele für Variablen- und Objektdeklarationen mit einer Startzuweisung sind (vor dem Typ stehen üblicherweise ein oder mehrere Qualifizierer.)

 

Qualifizierer oder Modifikatoren

Qualifizierer bestimmen, in welchen Objekten die Daten und Methoden einer Klasse zu sehen sind, bzw. von welchen Methoden sie aufgerufen oder geändert werden können (vgl. Guido Krügers Goto Java 2, Kapitel 7.4 ([JK07]) oder [B863] S. 241)

Beispiele für Qualifizierer

 

Arrays

In Java ist ein Array ein Objekt. Ein Array muss also während der Laufzeit mit new erzeugt werden. Die Deklaration und die Initalisierung sind: 

int[] wurf;
wurf = new int[6];

Mit jeder Datentyp und jedem Objekt kann ein Array erzeugt werden, d.h. eine lineare Reihung von Daten oder Objekten gleichen Typs, auf die mit einem Namen und einem Index in einer folgenden eckigen Klammer zugegriffen werden kann. Arrays sind spezielle Objekte und müssen vor Gebrauch deklariert werden. Und sie müssen wie alle Objekte mit new vor dem Gebrauch erzeugt werden. Der Parameter n, der dem Konstruktor bei der Erzeugung übergeben wird, bestimmt die Länge des Arrays. Die Indizes eines Arrays der Länge n laufen stets von 0 bis n-1. 

Mit der Methode length() erhält man die aktuelle Länge des Arrays, etwa n = wurf.length(). Auf die einzelnen Elemente kann mit wurf[i] zugegriffen werden. Dabei ist das erste Element stets wurf [0], und das letzte wurf[n-1]. Der Array-Index läuft also immer von 0 bis n-1, wenn ein Array n Elemente besitzt.

Dadurch, dass ein Array wie jedes Objekt zur Laufzeit erzeugt werden kann, ist ein Problem vieler Programmiersprachen (z.B. von Pascal oder Delphi) gelöst: Oft weiß man bei der Programmierung nicht, wie viele ähnliche Zahlen man benötigt, wie lang ein Array sein muss (siehe unten). In Java lässt sich das Problem recht einfach lösen: Man deklariert erstens eine Variable für ein Array, etwa mit: int[] wurf. (Jedes Objekt kann durch Anhängen von [] zu einem Array von Elementen dieses Objekts gemacht werden. - oder genauer: der Handle (Zeiger) auf ein Objekt kann durch Anhängen von [] zu einem Handle auf ein Array von Elementen dieses Objekts gemacht werden). Während der Laufzeit wird zweitens ein Parameter n gesetzt oder eingelesen. Mit wurf = new int[n] wird drittens während der Ausführung des Programms das entsprechende Array erzeugt. 

Beispiele für Deklarationen und Initialisierungen oder Erzeugen von Arrays

Bem: Die beiden Klammern [] können auch anstatt an den Datentyp an den Namen der Variable angehängt werden. 

Arrays lassen sich sehr leicht mit for-Schleifen manipulieren.

Hintergrund von Arrays: Bei vielen Programmen stellt sich das Problem, dass viele ähnliche Variablen benötigt werden, z.B. beim Berechnen von Primzahlen. Deshalb kennen alle erfolgreichen Programmiersprachen Arrays; allerdings in unterschiedlicher Ausprägung.

In Pascal (oder Delphi) muss bereits vom Programmierer vor dem Compilieren festgelegt werden, wie lang ein Array ist. Der Vorteil dabei ist, dass während des Compilierens überprüft werden kann, ob nur auf definierte Elemente zugegriffen wird. Der leicht einzusehende Nachteil ist, dass z.B. beim Berechnen von Primzahlen Probleme auftauchen, wenn der Benutzer erst entscheiden soll, bis zu welcher Zahl die Primzahlen berechnet werden sollen. 

In C kann die Länge eines Arrays während des Programmablaufs festgelegt werden. Dabei treten aber erfahrungsgemäß sehr viele Fehler auf, da Arrays in C nur Blöcke von Speicherplatz sind und der Compiler bei einem Zugriff auf ein Element nicht überprüft, ob der Speicherplatz Teil des Arrays ist oder ob in dem Speicherbereich bereits ganz andere Variablen abgespeichert wurden. Im letzten Fall treten dann oft nur sehr schwer nachzuvollziehende Fehler auf, da das Programm möglicherweise Daten nach dem Array überschreibt, wenn der Programmierer bei der Indexrechnung einen Fehler macht.

In Java werden die Vorteile von Pascal und C vereint. Dadurch dass ein Array ein Objekt ist, kann während der Laufzeit überprüft werden, ob der Speicherplatz auf den zugegriffen werden soll, Bestandteil des Objekts ist. Bei einem Fehlerfall bricht das Java-Programm mit einer relativ vernünftigen Fehlermeldung ab (siehe Exceptions). Allerdings bedeutet dies eine Verlängerung der Laufzeit des Programms.

 

Vector

Oft ist vor Durchlaufen eines Algorithmus nicht bekannt, wie viele Elemente in einem Array abgespeichert werden sollen. Ein Beispiel hierfür ist der Algorithmus, der die Anzahl der Teiler einer Zahl bestimmt. Selbstverständlich ist es möglich zuerst den Algorithmus einmal ohne Abspeichern zu durchlaufen, danach mit new das entsprechende Array zu erzeugen und abschließen den Algorithmus mit Abspeichern zu durchlaufen. Es liegt auf der Hand, dass dies nicht optimal ist. Eine andere durchaus häufig benutzte Variante ist, einfach ein möglichst großes Array zu erzeugen, das (hoffentlich) für alle praktischen Fälle ausreicht.

Die Lösung dieses Problems liefert das Objekt Vector. Der Anwender kann nach Deklaration und Erzeugung des Vectors dem Vector beliebig Objekte zuweisen, er kann den Vektor jederzeit verlängern. Java sorgt für eine dynamische Anpassung der Länge.

Der Overhead bei der Anpassung der Länge verlangsamt das Programm natürlich erneut. Zur Steigerung der Effizienz ist es mitunter sinnvoll den einfachen Konstruktor durch eine Variante zu ersetzen: Vector(initialCapacitiy) oder Vector(initialCapacity, cacityIncrement).

Die Elemente des Vectors müssen Objekte sein. Es können deshalb keine ganzen Zahlen vom Typ int sein. Sollen trotzdem Zahlen abspeichert werden, muss die Zahl zuerst in ein Objekt der Klasse Integer verwandelt werden. Dies geschieht mit new Integer(i), wenn die Zahl in der Variable i abgespeichert ist. Beispiele hierfür sind die Programme Teiler02 und PythagoraeischeTripel02.  

 

Inhaltsverzeichnis 
Java am GZG

Sprachelemente
Java am GZG