Kurzeinstieg Java: Klassen
↑Inhaltsverzeichnis
Einleitung • Grundlagen • Objektorientierung • Anhang
Methoden •
Klassen •
Vererbung •
Interfaces •
Polymorphie •
Aufzählungstypen •
Pakete •
Übungen
Wie sind Klassen aufgebaut?
[Bearbeiten]In diesem Abschnitt führen wir Sie in die Welt der Klassen ein. Es werden gleich zwei Klassen benutzt. Die Struktur der Klasse Testklasse
kennen Sie aus allen früheren Beispielen. Neu ist, dass nun eine zweite Klasse hinzukommt:
class Beispielklasse {
public static final int KONSTANTE = 42;
private static int anzahl = 0;
private String name;
public void sagNameUndAnzahl() {
System.out.println(String.format("Beispielklasse(%1$s) hat %2$d Instanz(en)", name, anzahl));
}
Beispielklasse(String n) {
anzahl++;
name = n;
}
}
public class Testklasse {
public static void main(String[] args) {
// Platz für 2 Beispielklassen
Beispielklasse[] klassenRaum = new Beispielklasse[2];
System.out.println("Kermit betritt den Raum...");
klassenRaum[0] = new Beispielklasse("Kermit");
klassenRaum[0].sagNameUndAnzahl();
System.out.println("Piggy betritt den Raum...");
klassenRaum[1] = new Beispielklasse("Piggy");
klassenRaum[0].sagNameUndAnzahl();
klassenRaum[1].sagNameUndAnzahl();
}
}
Das Beispiel enthält Beispielklasse
und Testklasse
. Beispielklasse
hat keinen Zugriffsmodifizierer während Testklasse
public
deklariert wurde.
Testklasse
erstellt zwei Instanzen von Beispielklasse
. Anschließend wird die Methode sagNameUndAnzahl()
für jede Instanz aufgerufen.
Beispielklasse
enthält eine Klassenkonstante namens KONSTANTE
(nicht verwendet), eine Klassenvariable namens anzahl
sowie eine Instanzvariable namens name
. Der Clou bei Klassenvariablen ist, dass sie über alle Instanzen hinweg denselben Wert haben. Das können Sie leicht an der Programmausgabe überprüfen. Die Instanzvariable wird nicht geteilt, jede Instanz hat ihren eigenen Wert für name
.
Ebenfalls enthält Beispielklasse
einen Konstruktor. Konstruktoren erkennt man daran, dass sie denselben Namen wie die Klasse haben. Dieser Konstruktor nimmt einen String entgegen und speichert ihn in der Instanzvariable name
. So kann die Methode sagNameUndAnzahl()
auf den Namen der Klasse zugreifen.
Wer darf was?
[Bearbeiten]In diesem Abschnitt geht es darum, welche Methode einer Klasse eigentlich auf welche Klasse- oder deren Methoden zugreifen darf. Es geht dabei auch um die relative Lage zweier Klassen zueinander. Nach diesem Abschnitt vergessen Sie bitte den Begriff der relativen Lage schnell wieder. Folgende relativen Lagen wollen wir unterscheiden:
- Paketebene: Es gibt ein Paket wie etwa 'gemeinsames.paket' in dem sich die Klassen A und B befinden. Beide Klassen gehören somit zum selben Paket. Paket selber ist eine Gliederungsebene oberhalb von Klassen. Mit Paketen befassen wir uns erst in einem späteren Kapitel.
- Verwandtschaftsebene: Zwei Klassen können in unterschiedlichen Paketen sein, aber miteinander verwandt. Das bedeutet, dass durch den später erläuterten Mechanismus der "Vererbung" die Klasse 'DarthVader' zum Vater von 'Luke' wird. In der Terminologie der objektorientierten Programmierung spricht man übrigens man eher davon, dass eine Klasse aus einer anderen abgeleitet wurde und es eine Super- und Subklasse gibt. Andere Sprechweisen sind möglich, wir vertiefen das später.
- Weltebene: Zwei Klassen teilen sich weder ein Paket noch sind sie miteinander verwandt. Sie haben einfach nichts miteinander zu tun.
Die gute Nachricht ist, es gibt ein paar einfache Fälle, die man unterscheiden kann. Besonders leicht ist es, wenn man bei einer einzelnen Klasse bleibt: Innerhalb einer Klasse darf nämlich jeder alles.
Auf private Attribute und Methoden kann von außen nicht zugegriffen werden. Damit ist private
der restriktivste Zugriffsmodifizierer.
Jeder auf Weltebene (und damit auch allen anderen Ebenen) darf auf mit public
gekennzeichnete Attribute und Methoden zugreifen.
Als package-private (deutschsprachiger Begriff gesucht) gilt ein Attribut oder eine Methode, wenn kein Zugriffsmodifizierer angegeben wurde. Das Zugriffsrecht haben nur Klassen, die im selben Paket liegen.
Mit dem Zugriffsmodifizierer protected
ist der Zugriff auf Verwandtschaftsebene erlaubt.
Wenn Sie der Einzige sind, der eine Klasse benutzt, dann spielt diese Frage keine Rolle. Im allgemeinen Fall verwendet man private
für Variablen sowie public
für Methoden, Konstruktoren und Datentypen. Eine Regel, die sich in der Praxis bewährt hat, lautet "so streng wie möglich, so freizügig wie nötig".
Gibt es noch weitere Modifizierer?
[Bearbeiten]strictfp
kennzeichnet Klassen und Methoden, deren enthaltene Fließkommaoperationen streng auf eine Genauigkeit von 32 bzw. 64 Bit beschränkt sind. Dadurch wird sichergestellt, dass die JVM darauf verzichtet, Fließkommaoperationen intern mit einer höheren Genauigkeit zu berechnen (beispielsweise 40 bzw. 80 Bit) und nach Abschluss der Berechnung wieder auf 32 bzw. 64 Bit zu kürzen. Dies ist wichtig, da es sonst bei verschiedenen JVMs oder verschiedener Hardware zu unterschiedlichen Ergebnissen kommen kann und somit das Programm nicht mehr plattformunabhängig ist.
Ausdrücke, die zum Zeitpunkt der Übersetzung konstant sind, sind immer FP-strict.
native
kann nur vor Methoden stehen und bedeutet, dass die Implementierung der betreffenden Methode nicht in Java, sondern einer anderen Programmiersprache geschrieben wurde, und von der virtuellen Maschine über eine Laufzeitbibliothek gelinkt werden muss. Die Syntax der Methode entspricht dann einer abstrakten Methode. Ein Beispiel:
public native void macheEsNichtInJava ();
Um eine solche Methode zu verwenden muss sie nach dem Compilieren von einen "Java-Pre-Compiler" (javah) bearbeitet werden. Dieser generiert aus einer nativen Methode einen entsprechenden C-Header und Funktionsrumpf, der dann mit Leben gefüllt werden kann. Diese Rümpfe werden als 'dll' unter Windows bzw. 'lib' unter Linux/Unix compiliert. Diese Bibliotheken müssen dann aber auch zur Laufzeit des Programms zugreifbar sein, andernfalls wird eine Ausnahme erzeugt.
What is this?
[Bearbeiten]Das Schlüsselwort this
bezieht sich auf Elemente einer Klasse. Es kommt beispielsweise zum Einsatz, wenn Parameter einer Methode und ein Attribut einer Klasse gleich lauten, wie im anschließenden Beispiel, oder bei "polymorphen Konstruktoren", die im Kapitel über Polymorphie vorgestellt werden.
class AllgemeineKlasse {
public final int x;
private final int y;
void zeigeInhalt() {
System.out.println(x + " " + y);
}
// Konstruktor
AllgemeineKlasse(int x, int y) {
this.x = x;
this.y = y;
}
}
In diesem Beispiel hat der Programmierer zwei Attribute der Klasse mit einzelnen Buchstaben benannt. Die Parameter des Konstruktors haben denselben Namen wie die Attribute. Die Zuweisung x=x
im Konstruktor schlug fehl, weswegen er das Schlüsselwort this
eingesetzt hat. Wir haben ihm trotzdem gekündigt[1].
this.x
hat hier die Wirkung von "das Attribut x in dieser Klasse" oder besser "… in diesem Objekt".
Auf this
kann man mit statischen Methoden nicht zugreifen, da this
immer an das Objekt gebunden ist – und Objekte gibt es im statischen Fall nicht.
- ↑ Siehe dazu das Kapitel über Programmierstile