9 Objekte und Klassen
· Sie können eine bestehende Klasse richtig interpretieren und anwenden.
· Sie können eine eigene Klasse deklarieren, die eine gegebene Spezifikation erfüllt.
· Sie setzen Konstruktoren zur Initialisierung von Objekten richtig ein.
· Sie können das Prinzip der Kapselung an Beispielen erklären.
· Sie können mit Objekten richtig umgehen.
· Sie können die Unterschiede zwischen Instanz- und Klassenvariablen erklären.
· Sie können das Überladen von Methoden anhand von Beispielen erklären.
· Rekapitulation
· Objekte = Daten und dazugehörige Methoden
· Objekte = Abbildungen von realen Dingen / Gegenständen oder gedachten Einheiten, die Eigenschaften (Daten) und Verhalten (Methoden) aufweisen
· OO-Programme bestehen aus einer Menge von Objekten, die zusammen eine gemeinsame Aufgabe bewerkstelligen.
· Daten (Attribute):
· bestimmen Eigenschaften und Zustand des Objektes
· Methoden (Operationen):
· Bestimmen Verhalten des Objektes (was kann man damit machen)
· Erlauben Zugriff auf die internen Daten des Objektes
· Beispiel: Ballon-Objekt
· Daten: x-, y-Koordinate, Durchmesser
· Methoden:
· Ändern des Durchmessers
· Darstellung: Gemäss OOP-Richtlinien ist jedes Objekt selbst dafür verantwortlich, sich dazustellen.
· Mit Objekten bzw. Klassen können zwei wichtige Konzepte bei der Programmierung realisiert werden:
· Kapselung: Daten und dazugehörige Methoden werden in einer Einheit zusammengefasst.
· Geheimnisprinzip:
· alle Information, die nur mit den „Innereien“ des Objekts zu tun haben, in den Objekten verstecken
· Eine klare Schnittstelle nach aussen definieren
· Schnittstelle bei Objekten:
· public-Methoden
· Die public-Methoden bilden die Schnittstelle der Objekte
· Sie ermöglichen den Zugang zu den öffentlichen Daten
· public-Variablen
· Als public deklarierte Variablen sind von aussen sichtbar und können auch von aussen verändert werden
· Wenn das Verhalten des Objekts vom Wert der Variablen abhängt oder Werte mehrerer Variablen untereinander gekoppelt sind, sollten diese Variablen nach aussen abgeschirmt werden, damit das Verhalten nicht unzulässig verändert werden kann
· sollten daher in der Regel vermieden werden! Wenn ein (lesender) Zugriff unbedingt nötig ist, dann über eine Zugriffs-Methode, die nur zulässige Operationen auf den Variablen erlaubt
· Die Schnittstelle von Objekten sollte möglichst nicht mehr geändert werden, wenn sie einmal festgelegt und publiziert ist. Grund: Jede Änderung an der Schnittstelle erfordert normalerweise Änderungen in den Programmen, die diese Objekte benützen.
· Verstecken:
· Daten und Methoden, die für die Benützung des Objektes nicht nötig sind, sollten wenn möglich vor dem Benützer versteckt werden. à private deklarieren.
· Vorteile:
· Durch die Kapselung stehen bei der Wiederverwendung neben den Daten gerade auch die dazugehörigen Methoden zur Verfügung.
· Durch den kontrollierten Zugriff auf die Daten via Zugriffs-Methoden bleiben die Daten der Objekte konsistent.
· Solange die Deklaration, d.h. der Header einer Methode unverändert bleibt, kann die Implementation der Methode kann jederzeit geändert werden, ohne dass der Benützer informiert werden muss.
· Dadurch wird die Abhängigkeit der Benützung eines Objektes von seiner Implementation (seinem Innenleben) möglichst gering gehalten.
· Beispiel: Objekt meinBallon
· Innenansicht:
private int diameter; private int xCoord, yCoord; public tuDasNicht; public void changeSize(int change){ int x, y; Anweisungen; } public void display(Gaphics g){ ... } private void flaeche(float d){ ..... } |
· Sicht von aussen (für den Benützer des Objektes):
public tuDasNicht; public void changeSize(int); public void display(Graphics); |
· Rekapitulation:
· Wir können Objekte nicht direkt programmieren, sondern nur die Klassen
· Eine Klasse ist ein Bauplan für Objekte (auch als Objektfabrik bezeichnet)
· Aus den Klassen werden zur Laufzeit konkrete Objekte erzeugt.
· Zur Compile-Zeit gibt es nur Klassen; zur Laufzeit gibt es nur Objekte.
· Aus derselben Klasse können beliebig viele (im Verhalten) gleichartige Objekte erzeugt werden.
· Ein Objekt wird auch als Instanz oder Exemplar der Klasse bezeichnet.
· Beispiel: Klasse für Ballonobjekte
· Bauplan:
· Klassendeklaration:
public class Balloon {
private int diameter;
private int xCoord, yCoord;
public Ballon(int initialDiameter,
int initialX, int initialY) {
diameter = initialDiameter;
xCoord = initialX;
yCoord = initialY;
}
public void changeSize(int change) {
diameter = diameter + change;
}
public void display(Graphics g) {
g.drawOval(xCoord, yCoord, diameter, diameter);
}
}
· Klassenname: Balloon
· Attribute (Daten):
Die Attribute der Klasse Balloon sind der Durchmesser und die Position des Ballons. Aus diesen Attributen werden zur Laufzeit die Variablen jedes Objekts, die sog. Instanzvariablen int diameter, xCoord, yCoord abgeleitet.
· Instanzvariablen werden als erstes in jeder Klasse deklariert, noch vor den Methoden
· Instanzvariablen können von jeder Methode der Klasse direkt zugegriffen werden
· Wir unterscheiden:
private:
– ausserhalb der Klasse nicht sichtbar
– Zugriff auf die Instanzvariablen nur via Methoden
· public:
– von aussen sichtbar und direkt zugreifbar
· Das Verhalten der Klasse (und damit ihrer Objekte) wird definiert durch deren Methoden („was kann ich mit diesen Objekten machen“):
· Grösse ändern, Ballon darstellen
· à public -Methoden changeSize, display
· Auch Methoden können private deklariert werden, z.B. dann, wenn sie klassenintern als Hilfs-Prozeduren verwendet werden
9.6 Erzeugung von Objekten
· „Erzeugen eines Objekts“ heisst, ähnlich wie bei der Deklaration von Variablen, den für ein Objekt benötigten Speicherplatz bereitzustellen. Für jedes Objekt wird wieder ein neuer Speicherbereich bereitgestellt, d.h. die einzelnen Objekte sind bezüglich ihrer Daten voneinander unabhängig.
· Initialisierung:
· Beim Erzeugen wird nur der Speicherbereich bereitgestellt, nicht aber dessen Inhalt. Daher: Alle Variablen müssen explizit initialisiert werden!
· Für Instanzvariablen gibt es dafür zwei Möglichkeiten
– direkt bei Deklaration
– in einer speziellen Methode für die Initialisierung von Objekten: à Constructor
· Konstruktor
· Ist eine spezielle Methode, die automatisch jedesmal aufgerufen wird, wenn ein Objekt erzeugt wird. (vgl. die Methode init() bei einem Applet!)
· Sie hat obligatorisch den gleichen Namen wie die Klasse und wird wie diese mit einem Grossbuchataben begonnen
· Sie hat keinen Resultattyp. Es wird aber trotzdem etwas zurückgegeben, nämlich ein Objekt der entsprechenden Klasse.
· Der Konstruktor hat, wie normale Methoden, eine Parameterliste (die auch leer sein kann)
· Für eine Klasse können mehrere unterschiedliche Konstruktoren deklariert werden, die sich durch ihre Parameter (Anzahl, Typen) unterscheiden (sog. Überladen, s. hinten)
· Mit einem Konstruktor können z.B. die Initialwerte der Instanzvariablen für jedes Objekt beim Erzeugen vorbesetzt werden. Bei der direkten Initialisierung der Instanzvariablen in der Klassendeklaration (z.B. int diameter = 20;) sind dagegen die Initialwerte für alle erzeugten Objekte gleich.
· Allgemeiner Aufbau einer Klassendeklaration:
public class Klassenname
{
Instanzvariablendeklaration(en)
Konstruktorendeklaration(en)
Methodendeklaration(en)
}
· Klassenname:
· Klassennamen gross beginnen
· Klassennamen sollten immer Substantive im Singular sein, eventuell durch ein Adjektiv ergänzt: Fahrzeug, MeinBallon
· Eine Klasse definiert einen neuen benützerdefinierten Datentyp. Im Gegensatz zu den einfachen Datentypen int, float, etc. ist eine Klasse ein sogenannter Referenzdatentyp
· Instanzvariablen
· Attribute à bestimmen Zustand, Eigenschaften der Objekte
· sind in allen Methoden der Klasse sichtbar
· Zugriff in der Regel private, in gewissen Fällen protected (Erklärung s. später)
· Achtung: nicht als public deklarieren!!
– gefährlich, da die Instanzvariablen dann von überall her veränderbar sind.
– sehr schlechter Programmierstil
· Methoden
· public
– bestimmen das von aussen sichtbare Verhalten des Objektes
– sind die Schnittstelle des Objektes nach aussen
· private
– nur für intern verwendete Methoden
– ausserhalb der Klasse nicht sichtbar
· Konstruktor (Constructor)
· [public] Klassenname (Parameterliste){
Konstruktorkörper
}
· Konstruktorkörper entspricht dem Methodenkörper bei Methoden
· Konstruktor wird automatisch aufgerufen, wenn ein Objekt erzeugt wird
· hat gleichen Namen wie Klasse
· hat keinen Resultattyp
· es wird trotzdem etwas zurückgegeben à ein Objekt der Klasse
· hat eine Parameterliste wie bei Methoden
· braucht nicht explizit als public deklariert zu werden, ist trotzdem überall sichtbar, wo die Klasse sichtbar ist
· falls kein Konstruktor deklariert wird, fügt Java automatisch einen sog. Default-Konstruktor ohne Parameter ein: Klassenname ()
· Wie wird jetzt ein Objekt erzeugt (instanziert) ? Auf den ersten Blick ähnlich wie eine normale Variable:
Balloon meinBallon;
Diese Anweisung erzeugt allerdings noch kein Objekt, sondern nur einen Behälter dazu, eine sog. Referenz. In der obigen Form ist die Referenz leer (enthält den Wert null). Um ein tatsächliches Objekt zu erzeugen, braucht es noch eine Zuweisung der Form
Balloon meinBallon = new Balloon(20,50,50);
Mit Balloon(20,50,50) wird der entsprechende Constructor aufgerufen; dieser erzeugt das Objekt, besetzt dessen Variablen mit den vorgegebenen Werten und liefert als Resultat dessen Referenz (= Speicheradresse) zurück, die in der „Variablen“ meinBallon gespeichert wird. Das Schlüsselwort new besagt dabei, dass ein neues Objekt erzeugt wird.
Mit der Anweisung
Balloon meinZweiterBallon = new Balloon(100,150,150);
kann ein weiteres Objekt mit andern Daten, aber dem gleichen Verhalten erzeugt werden.
· Lernaufgabe:
Schreiben Sie eine Klasse Kachel, wobei eine Kachel durch ein Rechteck gegeben ist. Ihre Lösung sollte folgendes enthalten:
· Attribute der Kachel: Grösse, Position und Farbe.
· Für jede Eigenschaft eine Methode, um diese zu verändern
(z.B. setPosition(int wert) )
· Einen parameterlosen Konstruktor, um die Farbe der Kachel zu initialisieren.
· Jede Klasse wird in ein separates File mit dem gleichen Namen wie die Klasse abgelegt. Dabei ist zu beachten:
· Der Filename muss gleich sein wie der Klassenname, einschliesslich der Tatsache, dass an dessen Anfang ein Grossbuchstabe steht. (Das Betriebssystem Windows kümmert sich zwar nicht darum; da gewisse Betriebssysteme hier jedoch unterscheiden, überprüft die JAVA-Entwicklungsumgebung – die ja auf den unterschiedlichsten Plattformen ablauffähig sein soll – diese Eigenschaft und meldet Fehler, wenn diese Regel nicht eingehalten wurde)
· die Klasse muss als public deklariert werden, da sie sonst von aussen nicht verwendet werden kann
· Vor der Klassendeklaration müssen die nötigen import-Statements stehen.
· Es können auch mehrere Klassen im gleichen File gespeichert werden. In diesem Fall muss folgendes beachtet werden:
· Eine (normalerweise die erste) Klasse muss public sein. Dies muss diejenige Klasse sein, die als Hauptklasse gelten soll (d.h. die z.B. das Applet darstellt)
· alle übrigen Klassen dürfen nicht public sein.
· Die import-Statements für alle Klassen müssen am Anfang des Files stehen.
· Mehrere Klassen im selben File sollten nur dann verwendet werden, wenn es sich um ein kleines Programm handelt, das keine weiteren Source-Files benötigt. Wenn das gesamte Source-File ein paar Druckseiten übersteigt, sollten die einzelnen Klassen besser je in einem eigenen File abgelegt werden.
· In jedem Fall erzeugt der Compiler pro Klasse ein .class-File (das den Bytecode enthält).
Wir konstruieren nun eine Klasse Balloon, die von einem Applet PlayBalloon verwendet wird. Dies deshalb, weil wir einerseits mit mehreren Ballonen spielen wollen, und anderseits, weil eine solche Klasse für sich allein noch kein lauffähiges Programm ergibt.
Zuerst das Applet PlayBalloon
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class PlayBalloon extends Applet
implements ActionListener {
private Button grow, shrink;
private Balloon myBalloon;
public void init() {
grow = new Button ("Grow");
add (grow);
grow.addActionListener(this);
shrink = new Button ("Shrink");
add (shrink);
shrink.addActionListener(this);
myBalloon = new Balloon (20, 50, 50);
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == grow){
myBalloon.changeSize(10);
}
if (event.getSource() == shrink){
myBalloon.changeSize(-10);
}
repaint();
}
public void paint (Graphics g) {
myBalloon.display(g);
}
}
Und jetzt die Klasse Balloon:
class Balloon {
private int diameter;
private int xCoord, yCoord;
public Balloon(int initialDiameter, int initialX, int initialY){
diameter = initialDiameter;
xCoord = initialX;
yCoord = initialY;
}
public void changeSize(int change){
diameter = diameter + change;
}
public void display(Graphics g){
g.drawOval(xCoord, yCoord, diameter, diameter);
}
}
· Übersicht:
· Programm besteht aus 2 Klassen: PlayBalloon und Balloon
· Aus beiden Klassen wird je ein Objekte erzeugt, wie unten beschrieben:
· Ablauf des Programms:
- Browser erzeugt ein Objekt der Klasse PlayBallon, indem er deren Default-Konstruktor aufruft, z.B: appObj = new PlayBallon(); dieser Konstruktor wird vom Compiler implizit erzeugt, obwohl der Programmierer ihn nicht definiert und auch nicht benutzen kann.
- Der Browser ruft die Methode init() des Applet-Objektes appObj auf:
– dort werden die Buttons grow und shrink erzeugt
– dann wird das Balloon-Objekt myBalloon erzeugt
- actionPerformed(ActionEvent e) wird jedesmal aufgerufen, wenn einer der zwei Buttons gedrückt wird:
– dort werden die Buttonereignisse behandelt.
– Die Methode event.getSource(); gibt das Objekt an, das das ActionEvent erzeugt hat.
- paint() wird jedesmal aufgerufen, wenn das Applet neu gezeichnet wird:
– ruft display-Methode von myBalloon auf
Diese Struktur eines Programms mit einem (GUI-orientierten) Applet-Objekt und einem (oder mehreren) daten-/verhaltenorientierten Objekt(en) wird uns in der Zukunft immer wieder begegnen.
Bei der Deklaration von Objekten haben wir eine etwas merkwürdige Doppelstruktur entdeckt: Zuerst wird eine sog. Referenzvariable deklariert, die als zweites mit einer Referenz auf das eigentliche Objekt gefüllt wird.
Die Variable „myBalloon“ enthält also gar nicht das Objekt selber, sondern nur einen Verweis darauf. Schreiben wir also
Balloon myBalloon;
so ist die Variable myBalloon leer, oder mit andern Worten, sie enthält den Wert null. Dieser Wert null ist ein Wert, den nur Referenzvariable enthalten können, und er besagt, dass die Variable derzeit „auf kein Objekt zeigt“. Wird mit einer derartigen Variablen auf ein (vermeintliches) Objekt zugegriffen, so wird das Programm mit einer Fehlermeldung abgebrochen (Exception).
Beim Umgang mit Objekten und deren Referenzvariablen ergeben sich somit einige wichtige Unterschiede im Vergleich zu normalen Variablen.
1. Zuweisung
Balloon myBalloon = new Balloon();
yourBalloon = myBalloon;
à Es wird nur die Referenz kopiert, nicht das Objekt selbst.
à myBalloon und yourBalloon zeigen deshalb auf das gleiche Objekt!
à Für das Kopieren von Objekten mus man spezielle Methoden aufrufen.
2. Methodenaufruf/Returnwert
Wird eine Methode wie folgt definiert:
private Balloon methodeA(Balloon b) {
b.changeSize(-10);
return b;
}
so wird für den Parameter b nur der Referenzwert übergeben, nicht das Objekt selber. Das heisst, dass zwar die interne Referenzvariable b eine Kopie der übergebenen Referenzvariable ist (s. unten: myBalloon), dass diese aber nicht etwa auf eine Kopie des Objekts, sondern auf das Originalobjekt selber zeigt, und dass somit – anders als bei normalen Variablen – Veränderungen am Objekt direkt aus der Methode heraus am Originalobjekt wirksam werden!
yourBalloon = methodeA(myBalloon);
à verändert die Grösse von myBalloon um -10.
à bewirkt, dass yourBalloon und myBalloon nun auf das identische Objekt zeigen.
Merke: Objekte werden nicht wie normale Variable als Kopie (by value), sondern als Referenz (by reference) auf das Original übergeben.
3. Mögliche Operationen mit Objekten (was kann man damit machen)
· Objekte kann man erzeugen, zuweisen und als Argument übergeben.
· Die normalen Operatoren (*, /, + , –, >, <, &&, etc.) funktionieren nicht mit Objekten (Ausnahme: Strings kennen den Operator +, siehe später) !
· Die einzigen Operatoren, die auch für Objekte gültig sind, sind == und !=. Diese haben aber nicht die gleiche Bedeutung wie bei einfachen Datentypen:
if ( myBalloon == yourBalloon) {...}
à vergleicht die Referenzen (Adressen der Objekte) der Objekte, nicht die Objekte selbst.
Dementsprechend ist die obige Bedingung nur wahr, falls myBalloon und
yourBalloon auf das gleiche Objekt zeigen.
– Beispiel:
String str1 = "abc";
String str2 = "abc";
str1 == str2 à ist immer falsch, da str1 und str2 zwei verschiedene Objekte
sind (auch wenn diese den gleichen Inhalt haben)
Um festzustellen, ob die zwei Strings str1 und str2 gleich sind, muss man die entsprechende Methode für den Vergleich von Strings verwenden (equals):
if ( str1.equals(str2) ){..} à ist in diesem Fall wahr
· Der Wert this:
In gewissen Fällen ist es notwendig, in einer Methode eine Referenz auf das eigene Objekt benützen zu können. Da zur Definitionszeit einer Klasse (Compile-Time) ja noch nicht bekannt sein kann, welches Objekt (zur Laufzeit) gemeint sein wird, kann man hierfür einen besonderen Referenz-Wert this benützen, der auf das Objekt zeigt, in welchem die betreffende Methode gerade abläuft. This ist so etwas wie eine Variable, die in jedem Objekt automatisch erzeugt wird und auf das Objekt zeigt, zu dem sie gehört. This kann nur gelesen werden, und der Programmierer kann keine Variable dieses Namens selber definieren.
Beispiel: Ein Constructor verwendet z.B. die gleichen Namen für Parameter, wie sie für Instanzvariablen ebenfalls gebraucht werden:
public class Balloon {
int diameter;
int xCoord, yCoord;
public Balloon(int diameter, int xCoord, int yCoord) {
// so geht es nicht:
diameter = diameter;
// sondern so:
this.diameter = diameter;
this.xCoord = xCoord;
this.yCoord = yCoord;
}
...
}
· Operator instanceof:
Für Objekte ist der zusätzliche Operator instanceof definiert. Er gibt an, ob ein Objekt zu einer bestimmten Klasse gehört oder nicht, z.B:
if ( event.getSource() instanceof TextField ) {...}
Diese Bedingung prüft, ob der aufgetretene Event, der mit getSource() ermittelt wird, von einem Objekt (einer Instanz) der Klasse TextField stammt.
· Methoden:
Neben diesen grundlegenden Operationen, die für alle Objekte definiert sind, bestimmen die Methoden der einzelnen Objekte, was man sonst noch alles mit ihnen machen kann. Sie bestimmen das eigentliche Verhalten des Objektes.
· Im Gegensatz zu einfachen Datentypen, die nur wenige Bytes im Arbeitsspeicher belegen, können Objekte unter Umständen sehr viel Speicherplatz belegen (z.B. Bilder oder Sounds!).
· Wenn der Programmierer alle Referenzen auf ein Objekt, das er erzeugt hat, löscht, dann kann er nicht mehr auf das Objekt zugreifen. Es belegt aber immer noch den Arbeitsspeicher, bis das Programm beendet ist.
· Falls Objekte nicht mehr gebraucht werden, sollte der belegte Speicherplatz möglichst rasch wieder freigegeben werden.
· Eine Möglichkeit besteht darin, dass der Programmierer im Programm selbst den belegten Speicher wieder zurückgibt (z.B. in Sprachen wie Pascal, C oder C++ usw.). Diese Methode ist aber sehr mühsam und fehleranfällig, muss doch der Programmierer genau Buch führen, welche Objekte er erzeugt und noch nicht zurückgegeben hat.
· Garbage Collection
· In Java (und einigen andern Sprachen) muss sich der Programmierer nicht um die Rückgabe des Speicherplatzes von Objekten kümmern, sondern
· die sogenannte Garbage-Collection (deutsch: Müllabfuhr), ein Prozess, der im Hintergrund läuft, entfernt automatisch Objekte aus dem Speicher, auf die es keine Referenzen mehr gibt.
· Einfache Datentypen
· Variablen einfacher Datentypen sind keine Objekte.
· Variablen einfacher Datentypen (boolean, int, float, double, etc.) sind nach der Deklaration sofort verwendbar, sie müssen nicht erzeugt werden.
· Zudem sind verschiedenste Operationen auf diesen Variablen vordefiniert (+, –, *, / etc.).
· Für die einfachen Datentypen sind (aus der Tradition) nur die eigentlichen Verarbeitungs-Operationen definiert (+, -, etc.). Eigentlich braucht der Programmierer aber auch noch andere Operationen wie z.B. das Umwandeln von Zahlen in Strings oder umgekehrt. Hierzu dienen sog. Wrapper-Klassen:
· Für die einfachen Datentypen werden sogenannte Wrapper-Klassen definiert. Beachte aber, dass deren Namen im Gegensatz zu den einfachen Typen gross geschrieben werden:
Boolean, Integer, Float, Double
· Variablen einfacher Datentypen können in Objekte der entsprechenden Wrapper-Klassen umgewandelt werden und umgekehrt.
· Diese Klassen definieren zudem verschiedene nützliche Methoden und Konstanten
· Konversion: toString, toHexString, valueOf etc.
· Parsing: parseInt etc.
· Min-/Maxwerte: MAX_VALUE, MIN_VALUE
· Eine Klasse kann mehrere Methoden mit demselben Namen haben.
· Solche Methoden werden beispielsweise gebraucht, wenn dem Benützer mehrere Methoden mit dem gleichen Zweck, aber mit mehr oder weniger Parametern (wobei die „fehlenden“ automatisch mit Default-Werten besetzt werden) angeboten werden sollen.
· Die Methoden müssen den gleichen Namen, aber jede eine unterschiedliche Parameterliste (unterschiedlich viele Parameter, oder unterschiedliche Parametertypen) haben, damit sie der Compiler trotzdem unterscheiden kann.
· Methoden mit nur unterschiedlichen Returntypen, aber gleichen Parameterlisten kann der Compiler nicht unterscheiden, da Resultattypen teilweise automatisch ineinander konvertiert werden können!
· Beispiel:
public void moveRight(int distance){
xCoord = xCoord + distance;
}
public void moveRight(){
xCoord = xCoord + 20;
}
moveRight(10); // à Methode 1
moveRight(); // à Methode 2
· Häufig wird das Überladen von Methoden bei Konstruktoren gebraucht, da dort der Konstruktorname vom Klassennamen vorgegeben ist. Beispiel:
· public Balloon(int initDiam, int initX, int initY) {...}
Mit diesem Konstruktor können alle Werte explizit gesetzt werden.
· public Balloon(int initX, int initY) {...}
Mit diesem Konstruktor können X und Y explizit gesetzt werden; für diameter wird ein default-Wert eingesetzt..
9.13.1 static – Variablen
Variablen, die zu Beginn einer Klasse definiert werden, werden automatisch zu Objektvariablen, wenn aus der Klasse ein Objekt angelegt wird. Damit erhält jedes Objekt „sein“ Exemplar von jeder Variablen und speichert darin unabhängig von allen andern Objekten der gleichen Klasse seine Werte. Es gibt jedoch Fälle, wo man genau dies verhindern will, d.h. erreichen will, dass alle Objekte der Klasse einen einzigen, gemeinsamen Wert einer Variablen benützen. Dies bewirkt man dadurch, dass man bei der Definition der Variablen das Prädikat static verwendet:
public class Balloon {
int diameter;
int xCoord, yCoord;
static int numberOfBalloons = 0;
public Balloon() {
numberOfBalloons++;
}
...
}
Mit der Einführung der Variablen numberOfBalloons als static kann man zählen, wieviele Objekte des Typs Balloon insgesamt erstellt wurden.
9.13.2 static – Methoden
Auch Methoden können mit dem Prädikat static deklariert werden; dieses bewirkt jedoch etwas anderes als bei Variablen: Als static deklarierte Methoden können verwendet werden unabhängig davon, ob es ein konkretes Objekt von der Klasse gibt oder nicht. Dies ist vor allem dann nützlich, wenn solche Methoden allgemein zur Verfügung gestellt werden sollen.
Klassisches Beispiel für Klassenmethoden: Alle mathematischen Methoden (Math.sin, Math.cos, etc.)
Aufruf von Klassenmethoden durch Voranstellen des Klassennamens (statt des Objektnamens wie bei den normalen Instanzmethoden):
x = Math.sqrt(y)
Aufgabe:
Ändern Sie die Klasse Kachel wie folgt:
· Alle Kachelobjekte sollen neu eine zwar variable, aber alle dieselbe Farbe haben.
· Schreiben Sie einen zusätzlichen Konstruktor, der eine quadratische Kachel einer bestimmten Grösse an einer bestimmten Position erzeugt.
· Zuerst Klasse definieren, dann Objekt instanzieren.
· Alle Variablen explizit initialisieren.
· Keine return-Anweisung in Konstruktoren. Returnwert ist implizit ein Objekt der Klasse.
9.15 Zusammenfassung
· Klassenstruktur
public class Klassenname
{
Instanzvariablendeklaration(en)
Konstruktorendeklaration(en)
Methodendeklaration(en)
}
· Konstruktor-Methoden
Hat denselben Namen wie die Klasse. Wird automatisch beim Erzeugen eines Objekts der Klasse ausgeführt. Kann in mehreren Varianten vorliegen (Überladen)
· Jede öffentliche Methode hat folgende Struktur:
public returnType methodName(parameters) {
// Implementation der Methode
}
· Um ein Objekt zu erzeugen, braucht es eine Referenzvariable, die mit dem Verweis auf das Objekt "gefüllt" wird; das Erzeugen des Objekts geschieht durch Aufruf des Konstruktors / eines seiner Konstruktoren:
ClassName objectName = new ClassName(parameters);
· Um eine Methode eines Objekts aufzurufen, wird der Name des Objekts und der Name der Methode, durch einen Punkt getrennt, geschrieben:
objectName.methodName(parameters);
· Eine statische Methode setzt man dann ein, wenn diese – unabhängig von allfällig davon existierenden Objekten – allgemein zur Verfügung stehen soll:
public static returnType methodName(parameters) { ... }
· Eine statische Methode wird aufgerufen, indem der Klassenname und der Name der Methode, durch einen Punkt getrennt, geschrieben werden:
ClassName.methodName(parameters);