Die wesentlichen Sprachelemente von Java werden hier - vor allem zum Nachschlagen - kurz zusammengestellt:
(Verantwortlich für die Seiten: W. Seyboldt / Stand: 11. Mai 2006)
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).
- 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.
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).
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.
| 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 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
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.
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.