Ein Java-Programm besteht aus einer oder mehreren Klassendefinitionen, die in Byte-Code in .class-Dateien übersetzt worden sind.
Einer der .class-Dateien enthält die Klasse, die die main-Methode definiert:
public static void main(String args[])
String args[]
enthält die Strings die auf der Kommandozeile übergeben worden sind. Anzahl: args.length().
Es existieren nur Felder (Attribute) und Methoden von Klassen. Jede Klasse ist Teil eines package.
Ein voll qualifizierter Java-Name besteht also aus
package_name class_name member_name
z.B.
java.lang.System.out.println("Hello World");
mit
Das package statement spezifiziert, daß Java-Code zu einem bestimmten Paket gehört.
Die import-Klausel erlaubt die abkürzende Schreibweise für zu qualifizierende Namen:
import java.util.Hashtable
erlaubt es, den Klassennamen Hashtable zu verwenden statt java.util.Hashtable.
statt dessen:
... public static final double PI = 3.14159; ...
if (false) { ... }
Ein optimierender Übersetzer wird solchen toten Code nicht mitübersetzen.
Java characters, strings und Bezeichner bestehen aus 16bit Unicode-Buchstaben.
Java führt zusätzliche Typen byte und boolean ein und legt für jeden primitiven Typ exakt seine Größe fest:
boolean | true or false | false | 1 bit |
char | Unicode character | ![]() | 16 bits |
byte | signed integer | 0 | 8 bits |
short | signed integer | 0 | 16 bits |
int | signed integer | 0 | 32 bits |
long | signed integer | 0 | 64 bits |
float | IEEE 754 float | 0.0 | 32 bits |
double | IEEE 754 float | 0.0 | 64 bits |
Nicht-primitive Werte in Java sind Objekte und werden über Referenzen adressiert. Werte von Grundtypen werden ``by value'' behandelt.
Zwei verschiedene Variablen können also auf das gleiche Objekt verweisen:
Button p,q; p = new Button(); q = p; // q zeigt auf den gleiche Button p.setlabel("OK"); // verändert auch q
das ist anders für Grundtypen
int i = 3; int j = i; i = 2; // das verändert j nicht
Sollen die Daten eines Objektes kopiert werden, muß dies explizit geschehen:
Vector b = new Vektor; c = b.clone();
Analog dazu vergleicht der Operator ``=='' nicht, ob zwei Werte gleich sind, sondern nur ob zwei Referenzen sich auf das gleiche Objekt beziehen. Wertgleichheit muß mit eigenen Methoden geprüft werden (z.B. equals()).
Vereinfacht die Sprache und verhindert viele Programmierfehler
Der Wert null steht für nicht vorhandene Referenz auf ein Objekt und kann an alle Variablen vom Klassen-, Interface- oder Array-Typ zugewiesen werden.
Mit new und Konstruktoren wie in C++:
java.awt.Button b = new java.awt.Button(); ComplexNumber c = new ComplexNumber(1.0, 1.414);
Besonderheit: Strings, obwohl nicht eingebaut sondern Bibliotheksklasse haben eine Sondernotation:
String s = "This is a test";
Java benutzt automatische Garbage Collection zur Freigabe von Objekten, die nicht mehr gebraucht werden, weil keine Referenz mehr auf sie existiert.
Zum Schutz kritischer Abschnitte, wenn mehrere threads aktiv sind, die gemeinsame Daten benutzen:
synchronized (expression) statement
Das Schlüsselwort synchronized kann auch als Kennzeichnung einer Methode benutzt werden, was die gesamte Methode zum kritischen Abschnitt macht.
Wenn eine Ausnahme nicht im Block behandelt wird, wo sie erzeugt wird, propagiert sie in den umfassenden Block, dann in die aufrufenden Methode, usw. bis zur main-Methode. Wird sie auch dort nicht behandelt, erzeugt der Java-Interpretierer eine Fehlermeldung und beendet die Ausführung.
Beispiel:
// Definition einer Exception-Klasse class IllegalAverage extends Exception{ public IllegalAverage() { super();} public IllegalAverage(String s) { super(s);} } // Eine Klasse, die diese Exception erzeugt: class MyClass { public double average(double [] vals, int i, int j) throws IllegalAverage { try { return (vals[i] + vals[j]) / 2; } catch (IndexOutOfBoundsException e) { throw new IllegalAverage(); } }
Irgendwo höher in der Aufrufkette kann es nun ein
catch (IllegalAverage e)
geben, das angemessen auf die Ausnahme reagiert.
Structs werden durch Klassen abgedeckt. Wichtige Eigenschaften von Vereinigungstypen können mit Klassenhierarchien simuliert werden. Das Fehlen von Aufzählungen in Java ist etwas erstaunlich.
Beispiel:
public class Circle { static int num_circles = 0; public double x,y,r; public Circle(double x, double y, double r) { this.x = x; this.y = y; this.r = r; } public Circle(double r) { this(0.0, 0.0, r); } public double area() { return 3.13159 * r * r; } }
Beobachtungen:
Java Begriff: Erweiterung (extension).
public class GraphicCircle extends Circle { Color outline, fill; public GraphicCircle(double x, double y, double r, Color outline, Color fill) { super(x,y,r); this.outline = outline; this.fill = fill; } public void draw(DrawWindow dw) { dw.draw(x, y, r, outline, fill); } }
Die Vererbung in Java ist Einfachvererbung. Jede Benutzer-Klasse hat genau eine Oberklasse. Wenn nicht spezifiziert, ist dies die vordefinierte Klasse Object.
Die Methodenbindung in Java ist dynamisch für in Unterklassen redefinierte Methoden.
Wenn eine Klasse eine abstrakte Methode (in C++ pur virtuelle) enthält, wird sie zur abstrakten Klasse.
Beispiel:
public abstract class shape { public abstract double area(); }
Regeln:
Abstrakte Klassen, die nur abstrakte Methoden und keine Attribute enthalten, lassen sich als Eigenschaftsklassen verwenden. Java führt hierfür das Sprachkonstrukt interface ein.
Beispiel:
public interface Drawable { public void setColor(Color c); public void setPosition(double x, double y); public void draw(DrawWindow dw); }
Konkrete Klassen implementieren Schnittstellenklassen, d.h. liefern Methodendefinitionen für die abstrakten Methoden der Schnittstellenklassen.
public class DrawableRectangle extends Rectangle implements Drawable { private Color c; private double x, y; ... public void setColor(Color c) { this.c = c; } public void setPosition(double x, double y) { this.x = x; this.y = y; } ... }
Wichtig: Die implements-Klausel kann mehrere Interfaces aufführen.