9. Eigene Klassen

 

 

Bis hierher haben Sie ausschliesslich Klassen verwendet, welche aus der Klassenbibliothek des SDK stammen (einzig die Programme selber waren ja eigene Klassen). Jetzt sollen Sie Ihre eigenen Klassen basteln und sie dann verwenden. Das Beispiel, an welchem Sie die Sache üben sollen, ist wieder das Thema Farben: Sie machen eine Eigene Farb - Klasse mit Ihrer (bzw. meiner) Lieblingsfarbe:

  • Erstellen Sie im Projekt Farben eine zweite Quelldatei namens MyColor.java (Rechtsklick auf den Ordner src und im Kontextmenü Add, New File wählen!) und versehen Sie mit dem folgenden Quelltext:

    class MyColor extends java.awt.Color {
       MyColor() {
          super(255,0,255);
       }
    }

Ihre eigene Klasse MyColor ist offenbar eine Unter-Klasse von Color. Mit "extends" zeigen Sie das an. Color ist also die Super-Klasse von MyColor, von der MyColor alles erbt. Ihre eigene Klasse erweitert Color nur ganz wenig, nämlich mit einem speziellen Konstruktor.  Einen Konstruktor definieren Sie, indem Sie den Klassennamen schreiben, gefolgt von runden Klammern. In der anschliessenden geschweiften Klammer definieren Sie den Konstruktor, sagen also, was geschehen soll, wenn eine Instanz Ihrer Klasse erzeugt wird. Unser Konstruktor hier ist sehr einfach: er ruft einen Konstruktor der Superklasse auf, nämlich den mit den drei Integer Zahlen in der Klammer. Das Schlüsselwort super steht dabei für den Namen der Superklasse, in unserem Falle Color. Maximal rot und maximal blau ergibt Magenta. MyColor() erzeugt offenbar die Farbe Magenta.

  • Übersetzen Sie die Klasse MyColor (Menü Build, Compile File) .
  • Öffnen Sie die Klasse Farben wieder und deklarieren Sie die Hintergrundfarbe anstatt vom Typ Color nun als vom Typ MyColor. Bei mir heisst das MyColor hinter;. Das Erzeugen der Instanz geschieht mit hinter = new MyColor();. Sie dürfen nichts in die runde Klammer schreiben, denn Ihr Konstruktor hat auch nichts in der runden Klammer. Das wäre bei Color nicht erlaubt: alle Konstruktoren von Color haben etwas in der runden Klammer und dieses etwas sind die Parameter.

  • Übersetzen Sie auch die Klasse Farben und lassen Sie das Applet laufen: Wenn der Hintergrund in Magenta erscheint, hat's geklappt.

  • Ergänzen Sie jetzt Ihre Klasse MyColor durch den folgenden zweiten Konstruktor:

  •  MyColor(int verdunkeln)
     {
       super(255-verdunkeln,0,255-verdunkeln);
     }


Dieser Konstruktor hat jetzt einen Parameter namens verdunkeln, welcher den Konstruktoraufruf für Color beeinflusst. Sie können so viele Konstruktoren definieren wie Sie wollen. Einzige Bedingung: Die Parameter der Konstruktoren müssen sich voneinander unterscheiden; es kann die Zahl der Parameter verschieden sein, aber auch nur der Typ.
 

  • Übersetzen Sie die Klasse MyColor wieder. Übrigens: Sie brauchen sich eigentlich gar nicht zu merken, welche Datei nun übersetzt werden muss: Wenn Sie Menü Build, Compile Project wählen (oder die Taste <F7> drücken, dann schaut JCreator selber nach, welche Dateien des Projektes geändert wurden und übersetzt werden müssen.

 
 
  • Ändern Sie in Farben die Instanzierung so ab, dass Sie den neuen Konstruktor von MyColor verwenden, z.B. hinter = new MyColor(150);. Damit erzeugen Sie eine Hintergrundfarbe Color(105,0,105) und Ihr Applet sollte nach Kompilation und Ausführung einen dunkeln Magenta - Hintergrund haben. Selbstverständlich können Sie in Farben gleichzeitig auch den ursprünglichen Konstruktor ohne Parameter verwenden um eine helle Magentafarbe z.B. für den Vordergrund zu erzeugen. Mein Applet sieht dann so wie das Bild rechts aus.

  • Die neue Klasse MyColor soll nun aber nicht nur die Eigenschaft haben, dass sie magenta ist, sie soll auch was können. Fähigkeiten verpassen Sie einer Klasse, indem Sie Methoden definieren. Schreiben Sie hinter den Konstruktoren von MyColor die folgende Methode:
 String farbName() {
    return "Magenta";
 }
  • Die Methode farbName() ist vom Typ String. Das heisst, dass sie nach ihrer Ausführung einen Wert von diesem Typ zurückgibt. Methoden, die von einem Typ sind müssen eine letzte Anweisung mit dem Schlüsselwort return haben. Hinter return steht, was die Methode zurückliefert, in unserem Falle ist das die String - Konstante "Magenta". Sie könnten nun in der Klasse Farben die Methode z.B. aufrufen mit String s = hinter.farbName();. Sie können diesen String aber auch direkt in das Applet schreiben, z.B.  mit g.drawString(vorder.farbName(),120,150);. Versuchen Sie's, aber passen Sie auf, dass Sie nicht etwa mit der Hintergrundfarbe auf Hintergrundfarbe schreiben oder ähnlich!

Auch Variablen kann Ihre Klasse natürlich enthalten. Die Farbe könnte sich z.B. merken ob sie dunkel ist oder nicht. Also deklarieren Sie am Anfang von MyColor boolean dunkel; In den Konstruktoren ergänzen Sie dann nach der Anweisung super(...); mit dunkel = false; bzw. dunkel = true;. Die Methode kann nun je nach dem zwei verschiedene Strings zurückgeben, z.B. folgendermassen:

if (dunkel) return "Dunkelmagenta"; else return "Magenta";

Und in Farben können Sie nacheinander die Vorder- und Hintergrundfarbe herausschreiben. Versuchen Sie's!

Das Wichtigste habe ich bei der Sache unterschlagen: Die Variablen wie z.B. dunkel, sollten unbedingtprivate deklariert werden, also z.B.:
private boolean dunkel;. Es hat zwar alles bestens funktioniert. Könnte aber sein, dass irgendein Programmierer (vielleicht Sie selber) den Wert der Variablen abändert (z.B. aus Versehen). Variablen und auch Methoden, die Sie mit dem Qualifizierer private versehen, sind nur in derjenigen Klasse bekannt, in der sie deklariert wurden. So kann ihnen nichts Böses geschehen und sie sind gegen aussen geschützt, man sagt dem auch abgekapselt. Sie sollten immer alles abkapseln, was nicht nach aussen bekannt sein muss. In unserem Falle ist das die Variable. Die Methode müssen wir von aussen, aus der Klasse Farben heraus, verwenden können. Also darf sie nicht private sein. Es ist ein guter Stil, nach Möglichkeit Variablen private zu deklarieren und ihre Werte mit Hilfe von Methoden nach aussen verfügbar zu machen - so wie ich es Ihnen soeben vorgeführt habe. Gerade die Tatsache, dass man in Klassen Dinge abkapseln kann, macht das objektorientierte Programmieren so erfolgreich.

 

 
  • Wie wär's, wenn sich die Farbe nicht nur merken würde ob sie verdunkelt ist, sondern auch noch um wieviel? Deklarieren Sie dazu eine zweite Variable, geben sie ihr im Konstruktor den richtigen Wert, schreiben Sie eine zweite Methode, welche diesen Wert liefert und schreiben Sie ihn ins Applet. Das könnte dann etwa so aussehen:

Falls Sie allzusehr Mühe haben mit diesem Programm: meine Lösung finden Sie hier.

Drucken Sie die Besprechung.

Noch zwei Ergänzungen:

Fields: Variablen, welche in einer Klasse deklariert sind heissen Felder oder fields, im Unterschied zu Variablen, welche in Methoden deklariert sind (was offenbar auch möglich ist!). Fields sind in der ganzen Klasse bekannt, Variablen einer Methode aber nur in der Methode selber.

Vordefinierte Farben: In der Klasse Color sind eine Reihe gebräuchlicher Farben als fields schon vordefiniert.

  • Klicken Sie irgendwo auf das Wort Color im Editor, drücken Sie die Tastenkombination <Ctrl>+<F1>, scrollen Sie dort bis zum "Field Summary": Sie sehen alle vordefinierten Farben. Sie können also z.B. mit setBackground(Color.pink); die Hintergrundfarbe auf rosa setzen - probieren Sie's aus, wenn Sie Lust haben


 

 

 

 

Spielereien mit Bildern: Ich habe schon erwähnt, dass man in Applets besonders einfach Bilder einfühgen kann. Bilder sind Instanzen der Klasse Image. Ein Bild holen Sie in ein Applet mit der Methode getImage(), deren Rückgabewert eine Instanz von Image ist. Eine kleine Komplikation: Der Parameter von getImage() ist eine URL (Webadresse, dazu später mehr). Die URL der .htm Datei des Applets liefert getDocumentBase() (ohne Dateiname). Den Dateinamen können Sie bei getImage() als zweiten Parameter als String angeben. Konkret sieht das dann folgendermassen aus:

  • Erstellen Sie ein neues Applet Projekt oder ändern Sie das Projekt Farben ab.
  • Kopieren Sie das Bild smilyCrazy.jpeg oder ein anderes .jpg oder .gif Bild in den Ordner classes.
  • Deklarieren Sie im Applet eine Image - Variable, z.B. Image img;
  • In die Methode init() kommt folgende Anweisung: img = getImage(getDocumentBase(),"smilyCrazy.jpeg");
    init() wird übrigens beim Start des Applet ausgeführt!
  • In der Methode paint() schreiben Sie dann g.drawImage(img,0,0,this);
  • Übersetzen Sie und führen Sie aus: Schon sollte das crazy Smily zu sehen sein!
  • So etwas wie das Bild rechts erhalten Sie, wenn Sie das Bild z.B. 100 mal in einer for Schlaufe darstellen, an verschiedenen Positionen. Denken Sie an die Methode Math.random(), welche Ihnen Zufallszahlen zwischen 0 und 1 liefert und dass Sie so eine Fliesskommazahl mit (int) in einen Integer umwandeln können
  • Lustig sieht die Sache übrigens aus, wenn Sie das Bild in einem unendlichen Loop immer wieder darstellen. Speichern Sie vorher alles. Einen unendlichen Loop erhalten Sie z.B. mit while (true). Sie stoppen das Applet am besten im schwarzen Fenster mit <Ctrl>+<c>.
  • Noch psychedelischer wird's, wenn Sie Musik abspielen dazu:
    play (getDocumentBase(), "spacemusic.au");
    Die Audiodatei spacemusic.au muss wie das Bild im Ordner classes sein. Damit Sie was hören muss ich Ihnen einen Kopfhörer aus dem Schrank geben. Leider kann das Stück mit unseren Kenntnissen nur einmal abgespielt werden. Hier wäre noch eine Wave - Datei: CHIMES.WAV. Und hier noch eine MIDI Datei: Mond.mid. Auf direktem Weg können wir leider keine .mp3 Dateien abspielen, aber sonst haben wir jetzt schon (fast!!!) unseren eigenen Mediaplayer. Mehr zu Bildern und Musik folgt später.