• Keine Ergebnisse gefunden

Einführung in die Programmiersprache JAVA

N/A
N/A
Protected

Academic year: 2022

Aktie "Einführung in die Programmiersprache JAVA"

Copied!
42
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Einführung in die Programmiersprache

JAVA

unter Verwendung der Entwicklungsumgebung

BlueJ

Text von K.Spier (2004), überarbeitet von B.Spier (2009-2014)

(2)

Inhaltsverzeichnis

Kapitel 1: Vorstellung der Entwicklungsumgebung BlueJ und erstes Projekt ... 3

Installation ... 3

Projekt Beispiel_1 (Quader) ... 4

Der Editor von BlueJ für JAVA-Quelltexte ... 5

Kapitel 2: Zweites Projekt: Bankkonto (Bank_1) ... 8

Erstellen einer vollständigen Übersicht zur Klasse 'Konto' (Dokumentation) ... 10

Kapitel 3: Drittes Projekt: Bank_2 ... 11

Informationen zu private und public ... 15

Kapitel 4: Viertes Projekt: Fahrkartenautomat ... 16

Zahlen formatieren ... 17

Kapitel 5: Fünftes Projekt: Person (Vererbung / GregorianCalendar) ... 18

Vererbung ... 21

Überschreiben von Methoden ... 22

Kapitel 6: Sechstes Projekt: Wir programmieren ein Applet ... 24

Aufbau eines HTML-Quelltextes ... 25

Kapitel 7: Siebentes Projekt: Das Applet reagiert auf eine Maus-Aktion ... 27

Kapitel 8: Achtes Projekt: Das Puzzle mit 25 Feldern ... 32

Klassenvariablen und Instanzvariablen ... 32

Array ... 33

For-Schleife ... 34

Start und Stop ... 34

While-Schleife ... 35

Kapitel 9: Was haben wir jetzt gelernt? (Wdh. und kleine Ergänzungen) ... 37

(Klassen, Variablen, Methoden, Konstruktoren, Fallunterscheidung, Schleifen) Kapitel 10: Schlussbemerkung ... 39

Anhang ... 40

JAVA-Programm ohne Entwicklungsumgebung erstellen ... 40

Listen, die nur Instanzen einer einzigen Klasse verwalten... 41

Formatierungen von numerischen Werten (2 Beispiele für String.format)... 42

(3)

Vorbemerkung

Mit JAVA wurde eine objektorientierte Programmiersprache entwickelt, die unabhängig vom Betriebssystem des Computers ist, auf dem die Programme laufen. Es gibt viele so genannte Entwicklungsumgebungen, um JAVA-Programme zu erstellen. Eine Entwicklungsumgebung ist zwar nicht Voraussetzung zum Programmieren – JAVA-Programme ließen sich auch mit einem einfachen Texteditor erstellen. Mit einem Compiler können daraus Dateien erstellt werden, die ein JAVA-Runtime-Environment ausführen kann, solche Datei kann also ein fertiges Programm aufge- fasst werden. Mit Hilfe einer Entwicklungsumgebung können Quelltexte sowohl erstellt als auch kompiliert und ausgeführt werden, dadurch sind die Arbeitsschritte erheblich einfacher und übersichtlicher. Außerdem ist der Editor dann üblicherweise mit Syntaxhervorhebung (s. S. 5) versehen, so dass die Programmstruktur besonders gut sichtbar wird. Interessierte finden im Anhang eine kurze Beschreibung, wie man auch ohne Entwicklungsumgebung ein JAVA-Programm erstellen kann.

Für den Einstieg in das Programmieren mit JAVA ist BlueJ besonders gut geeignet.

1. Vorstellung der Entwicklungsumgebung BlueJ und erstes Projekt JAVA installieren

JAVA wird durch Ausführen der Datei jdk-7u25-windows-i586.exe1 oder auf 64-Bit-Systemen

jdk-7u25-windows-x64.exe installiert. (Ein Java-Runtime-Environment jre..., das mit OpenOffice, Geogebra oder anderen Programmen vielleicht bereits installiert ist, genügt nicht – für BlueJ wird ein Java-Development-Kit jdk... benötigt. Für Download nach java se downloads oder jdk suchen!) JAVA muss vor BlueJ installiert werden.

BlueJ installieren

BlueJ darf für Bildungszwecke verwendet werden ohne dass Lizenzgebühren zu zahlen sind. (Siehe Homepage von BlueJ, http://www.bluej.org,Download der Version 3.1.02 von dort.)

Zur Installation wird die Datei bluejsetup-308.msi2 ausgeführt. Beim ersten Programmstart sucht BlueJ die zu verwendende JAVA-Version und zeigt eventuell ein Auswahlfenster, wenn die Zuordnung nicht automatisch erfolgen kann.

Spracheinstellung: Deutsch

Wenn die Entwicklungsumgebung in deutscher Sprache erscheinen soll, muss die Datei BlueJ.defs

mit einem Text-Editor bearbeitet werden, geeignet ist z.B. WordPad (Startmenü/Zubehör). Dieser Editor muss bei aktuellen Windows-Versionen als Administrator ausgeführt werden, damit im Installationsordner (vermutlich: C:\Programme(x86)\BlueJ\) Schreibberechtigung erreicht wird.

BlueJ.defs liegt im Unterverzeichnis lib des Installationsordners von BlueJ. Zum Öffnen muss als Dateityp „Alle Dokumente (*.*)“ eingestellt werden.

In dieser Datei findet man (ungefähr Zeile 31) die Festlegung der Sprache: Hier kann bluej-language=english in bluej.language=german geändert werden. Danach wird die Datei gespeichert.

1 Aktuelle Version im August 2013 2 Aktuelle Version im August 2013

bluej.language=english wird zu:

bluej.language=german

(4)

Ein Projekt beginnen: Projekt Beispiel_1

Wir starten BlueJ und wählen den Menüpunkt

Projekt/Neues Projekt.

Es erscheint das Dialogfenster, in dem wir angeben, wo das Projekt gespeichert werden soll. Ein Projekt besteht immer aus mehreren Dateien, deshalb wird für jedes Projekt ein eigener Ordner angelegt.

Ordner, die ein BlueJ-Projekt enthalten, werden von BlueJ durch ein spezielles Symbol gekennzeichnet (siehe Abbildung).

Mit dem Schalter „Erzeugen“ wird der Ordner mit dem eingegebenen Namen angelegt und die Projektdateien werden darin gespeichert.

Die Arbeitsfläche von BlueJ enthält zunächst nur ein Symbol für eine Readme-Datei, die für eine Beschreibung des Projekts vorgesehen ist. Nicht nur im Schulunterricht macht es Sinn, in einer solchen Datei eine ganz knappe Beschreibung des Projektes anzugeben. Die Datei wird mit einem Doppelklick auf das Symbol geöffnet, dann bearbeitet, gespeichert und wieder geschlossen.

Nun werden wir als erstes Beispiel eine Klasse mit Namen 'Quader' erstellen (wie im Info-Kasten oben rechts).

Eine Klasse im Projekt erstellen

Wir klicken auf den Schalter Neue Klasse und geben als Namen für diese Klasse Quader ein. Daraufhin erscheint ein neues Symbol für diese Klasse in der Projektübersicht. Wir klicken doppelt auf dieses

Symbol, um die Klasse zu bearbeiten. Zunächst sehen wir schon einige Zeilen vorgegebenen Text im Editor für unseren Java-Quelltext, den wir nach unseren Erfordernissen anpassen werden (einige Zeilen löschen, andere ergänzen).

Info:

In der objektorientierten Programmierung arbeitet man mit Objekten. (logisch)

Objekte können Eigenschaften haben.

Beispiel:

Ein Quader hat die Eigenschaften Länge, Breite, Höhe. Diesen Eigenschaften können verschiedene Werte zugeordnet sein. Ein zweiter Quader hat die gleichen Eigenschaf- ten, aber mit anderen zugeordneten Werten.

Ein Zylinder hat dagegen andere Eigenschaf- ten, denn er ist durch Radius und Höhe bestimmt.

Alle Quader können wir zu einer Klasse zusammenfassen:

Wenn wir eine Klasse 'Quader' definieren, dann legen wir darin eine Art „Bauplan“ fest.

Alle Quader sind Objekte, die nach diesem Bauplan konstruiert werden.

In der Definition der Klasse 'Quader' wird außer den Eigenschaften Länge, Breite, Höhe auch eine Methode zum Erzeugen von Quader-Objekten festgelegt, sie wird als Konstruktor oder Constructor bezeichnet.

Anmerkungen:

1. Die genannten Begriffe werden allgemein bei der objektorientierten Programmierung verwendet – unabhängig davon, ob man z.B.

mit JAVA oder mit Delphi arbeitet.

2. Gelegentlich sagt man auch, in der Definition einer Klasse wird der Objekt-Typ beschrieben, und das danach konstruierte Objekt wird auch als Objekt-Instanz bezeichnet.

(5)

Der Editor von BlueJ für JAVA-Quelltexte

Der Editor arbeitet mit sogenannter Syntax- Hervorhebung, d.h.

dass z.B. reservierte Wörter oder Kom- mentare in bestimmter Weise farblich hervor- gehoben werden.

Die Tatsache, dass hier der größte Teil des Textes in blau dar- gestellt ist, zeigt bereits, wie wichtig Kommen- tare in Computerpro- grammen sind.

Bei genauem Hinsehen können wir sogar zwei verschiedene Arten von Kommentaren unter- scheiden:

Einfache Kommentare werden mit zwei Schrägstrichen einge- leitet und dienen oft dem Programmierer als Notiz.

Die anderen, die mit

/** eingeleitet, mit *

fortgesetzt und mit */

beendet werden, dienen zusätzlich zur Informa- tion für andere – darauf wird später näher einge- gangen (Seite 10). Auf die Begriffe public und

private wird ebenfalls später eingegangen (Seite 15). Wir sehen, dass die Klassendefi- nition mit dem Wort

class eingeleitet wird, gefolgt vom Namen der Klasse.

Dann folgt eine öffnende geschweifte Klammer, die zugehörige schließende Klammer steht in der letzten Zeile.

Der BlueJ-Editor gestaltet nicht nur den Schriftstil, er hebt auch die Struktur durch die Hinter- grundfarbe hervor (z.B. Texte innerhalb eines {}-Klammerpaares).

(6)

Zum Aufbau dieses Programm-Quelltextes:

Nach dem Klassennamen werden im obigen Beispiel die Eigenschaften (hier: Variablen) für die Instanzen festgelegt: Jede Instanz, die wir gemäß diesem „Bauplan“ erzeugen, soll je eine Variable für Länge, Breite und Höhe besitzen. Der Variablentyp wird in JAVA immer dem Variablennamen vorangestellt. Hier wird int als Variablentyp angegeben, d.h. die aufgeführten Variablen sind vom Typ „integer“, sie können nur ganzzahlige Werte aufnehmen. (Wir folgen damit dem Vorschlag von BlueJ für die Variablentypen, andere lernen wir später kennen.).

Da diese Variablen hier den Instanzen zugeordnet sind, heißen sie auch Objektfelder oder Datenfelder oder auch Instanzvariablen.

In Java sind auch Umlaute in Variablennamen zugelassen. Umlaute werden jedoch nicht in allen

Entwicklungsumgebungen (bzw. Betriebssystemen, z.B. Linux) gleich codiert. Die BlueJ-Version 3.0.5 kann zwar Quelltexte übersetzen, in denen Methoden- oder Klassen-Bezeichner Umlaute enthalten, jedoch führen Methodenaufrufe dann zu Fehlern. Variablen-Bezeichner können Umlaute enthalten, ohne dass es zu Fehlern kommt. Version 3.0.8 kann offenbar gut mit Umlauten umgehen. Die Vermeidung von Umlauten und anderen Sonderzeichen ist dennoch zu empfehlen.

Es folgt die Festlegung des Standard-Konstruktors. Der Name des Konstruktors stimmt in JAVA immer mit dem Namen der Klasse überein. Dieser Konstruktor ist hier sehr einfach aufgebaut: Er legt nur Werte für die Variablen eines Quaders fest, der mit ihm erzeugt wird. Alle Quader- Instanzen, die mit diesem Konstruktor erzeugt werden, haben die gleichen Werte für die Höhe, die Länge und die Breite. Für die Zuweisung von Werten an eine Variable wird in JAVA ein einfaches Gleichheitszeichen verwendet (wie in BASIC, C++, aber anders als in PASCAL u. DELPHI). Auch für den Konstruktor werden Anfang und Ende durch öffnende bzw. schließende geschweifte Klammer gekennzeichnet. Beachten Sie die übersichtlichen Positionen aller {}-Klammerpaare!

Das Beispiel zeigt außerdem, dass eine Klasse mehrere Konstruktoren besitzen kann: Ein zweiter Konstruktor dient dazu, Quader zu konstruieren, bei denen mit Aufruf des Konstruktors Werte für die Länge, die Breite und die Höhe erfragt und übernommen werden.

Zum Schluss zeigt das Beispiel, dass die Klasse außer Konstruktoren auch noch andere Methoden besitzen kann, hier zur Berechnung des Volumens. Diese Methode berechnet aus Länge, Breite und Höhe der Quader-Instanz ihr Volumen. Durch die Angabe von return wird festgelegt, welcher Wert bei Aufruf dieser Methode zurückgegeben wird. Bei allen Methoden, die einen Wert zurückgeben, muss vor dem Namen der Methode – ähnlich wie bei Variablen – der Typ des Rückgabewertes angegeben werden, hier also int für integer (ganzzahlig).

Wenn wir die Klasse 'Quader' so wie oben beschrieben festgelegt haben, lassen wir diesen Text übersetzen (auch als compilieren bezeichnet, Schalter links oben, Shortcut Strg-k). Dabei wird dieser Text in einen vom Computer interpretierbaren Code übersetzt. Beim Compilieren zeigen sich (nicht nur bei Anfängern) oft kleine Fehler, die eine Übersetzung verhindern, z.B. eine fehlende Klammer, ein fehlendes Semikolon oder ähnliches.

Nach dem Kompilieren der Klasse 'Quader' werden wir mit Hilfe von BlueJ Instanzen zu dieser Klasse erzeugen und untersuchen.

Tipp 1:

Da zu jeder öffnenden geschweiften Klammer eine schließende gehört, ist es vernünftig, nach der öffnenden auch gleich die schließende (in der nächsten Zeile) zu tippen. Den weiteren Text kann man dann dazwischen einfügen.

Tipp 2:

Einrückungen wie im Beispiel sind für die Interpretation des Quelltextes zwar nicht erforderlich, sie werden aber für die Übersichtlichkeit (auch von Profis) vorgenommen. Da die Programme mit zunehmendem Lernfortschritt komplizierter werden, sollte man sich diesen Stil von Anfang an zu Eigen machen.

Beobachten Sie, wie BlueJ nach der öffnenden Klammer automatisch einrückt und die schließende Klammer an die passenden Position setzt! (Editor-Menü Bearbeiten, Befehl Auto-Layout, Shortcut Strg- Umschalt-I!) Die Einrückposition für Kommentare erreicht man am einfachsten mit der TAB-Taste.

(7)

Instanzen der Klasse Quader erzeugen

Wenn die Klasse 'Quader' erfolgreich com- piliert wurde, ist das Symbol für diese Klasse nicht mehr schraffiert. Um nun eine Instanz von dieser Klasse zu erzeugen, klicken wir mit der rechten Maustaste auf das Klassensymbol. Aus dem sich öffnen- den Kontextmenü wählen wir zunächst new Quader() aus. Der (Standard-) Konstruktor wird ausgeführt, nachdem wir einen Namen für die Instanz festgelegt haben. Auf dem Hauptfenster erscheint unten ein Symbol für das soeben erzeugte Objekt. Wir können den Vorgang wiederholen und somit wei- tere Instanzen derselben Klasse erzeugen.

Wählen wir das nächste Mal aus dem Kontextmenü new Quader(la,br,ho) aus, so werden wir zum Ausführen des zweiten Konstruktors nach den Werten für die Parameter

la, br und ho gefragt: Im oberen Abschnitt des Dialogfensters wird der Kom- mentar angezeigt, der im Quelltext dem Konstruktor vorangestellt worden war.

Klicken wir nun mit der rech- ten Maustaste auf ein rotes Objektsymbol, so können wir u.a. aus dem Kontextmenü

auswählen, ob wir das Objekt löschen oder untersuchen (inspizieren) wollen. Das Inspi- zieren zeigt uns, welche Werte die Variablen

laenge, breite und hoehe besitzen. Außerdem

können wir über das Kontextmenü die Methode zur Volumenberechnung aufrufen. (Dort gezeigte geerbte Methoden interessieren an dieser Stelle nicht.)

Fragen und Aufgaben zum Text

1. Braucht man BlueJ, um Programme in JAVA zu schreiben?

2. Der Begriff Objekt wird manchmal sowohl für Klasse als auch für Instanz verwendet. Erläutern Sie diese Begriffe an dem hier vorgestellten und an einem anderen selbst gewählten Beispiel.

3. Muss eine Klasse einen Konstruktor besitzen? (Probieren Sie es mit einem Testprojekt aus!) 4. Kann eine Klasse verschiedene Konstruktoren besitzen?

5. Was ist im Quader-Quelltext der Unterschied zwischen la und laenge?

6. Ergänzen Sie in der Klasse 'Quader' ein Datenfeld rauminhalt und eine Methode public void berechneRauminhalt(), die aus laenge, breite und hoehe den Rauminhalt berechnet und in das Datenfeld rauminhalt einträgt. [Erläuterungen zu void folgen im nächsten Kapitel.]

7. Testen Sie die Methode von Aufgabe 6, indem Sie eine Quaderinstanz vor und nach Ausführen dieser Methode untersuchen (inspizieren).

(8)

2. Zweites Projekt: Bankkonto (Bank_1)

In diesem Projekt werden wir eine Klasse 'Konto' erstellen. Dann werden zwei Instanzen dieser Klasse erzeugt, die Girokonten darstellen sollen. Mit Hilfe geeigneter Methoden sollen Einzahlungen und Abhebungen vom Girokonto möglich sein, aber auch Überweisungen von einem Konto auf das andere.

Vorüberlegungen zur Klasse 'Konto'

Zunächst überlegen wir uns, welche Eigenschaften für Konto- Instanzen in dieser Klasse festgelegt werden müssen: Ein Konto besitzt auf jeden Fall eine Kontonummer, einen Kontoinhaber und einen Kontostand. Wir benötigen eine Methoden zum Einzahlen, eine zum Abheben, eine zum Überweisen. Aber auch zum Auslesen des Kontostands werden wir eine Methode verwenden. Diese Vorüberlegungen („Entwurf eines Modells“) sind von der Programmiersprache noch weitgehend unabhängig.

Erstellen des Konto-Projekts in BlueJ:

Wir starten BlueJ und beginnen ein neues Projekt, dem wir den Namen Bank_1 geben (ein weiteres Bank-Projekt werden wir

dann Bank_2 nennen). Beachten Sie die Hinweise zur Readme.txt–Datei sowie zu den Kommentaren vom ersten Beispiel.

Bei den Variablen (Datenfelder) lernen wir neue Datentypen kennen (bisher wurde nur int verwendet): Der Typ double lässt zu, dass Zahlen mit Dezimalkomma (bzw. Dezimalpunkt) als Wert zugewiesen werden können. Für den Kontoinhaber soll ein Name zugewiesen werden und nicht eine Zahl oder Nummer. Hier wird der Typ String verwendet. Genau genommen ist String gar kein Variablentyp, sondern eine Java-Klasse, damit wird auch der Großbuchstabe am Wortanfang gerechtfertigt. In JAVA wird im Gegensatz zu einigen anderen Programmiersprachen zwischen Groß- und Kleinbuchstaben unterschieden. Klassennamen beginnen üblicherweise immer mit einem Großbuchstaben. Variablen- und Methodennamen beginnen üblicherweise mit einem Kleinbuchstaben. Zur Verbesserung der Lesbarkeit werden bei Wortzusammensetzungen oft mitten im Bezeichner Großbuchstaben verwendet (zum Beispiel getKontoStand ).

Die Datenfelder werden am Beginn der Klasse festgelegt (wie auch bei der Klasse 'Quader'). Der einfachste Konstruktor könnte als Kontonummer und Kontostand jeweils den Wert 0 zuweisen, als Kontoinhaber "" oder "dummy". Das ist für das Erzeugen mehrerer Konto-Instanzen natürlich nicht sinnvoll – also wird man dafür sorgen, dass gleich beim Erzeugen einer Konto-Instanz nach dem Namen und der Kontonummer gefragt wird. Der Kontostand kann mit 0 initialisiert werden, aber auch die Kontoeinrichtung mit einem Startguthaben könnte vorgesehen werden.

'Konto' besitzt nach diesen Überlegungen 3 Datenfelder und 5 Methoden (eine davon ist der Konstruktor), vergl. Kasten oben links. Es folgt der Quelltext für dieses Projekt (im folgenden werden Quelltexte nicht als Screenshot dargestellt, sondern als Text mit Syntax-Hervorhebung; hier außerdem mit Zeilenummern):

1: /**

2: * Es wird eine Klasse 'Konto' programmiert.

3: *

4: * @author B. Spier 5: * @version 15.11.2009 6: */

7: public class Konto

8: { // Instanzvariablen (Datenfelder)

Modell der Klasse 'Konto':

Klasse:

Konto Felder:

ktoNummer (int) ktoInhaber (String) ktoStand (double) Konstruktor:

Konto(ktoNr,ktoInh) Methoden:

einzahlen() abheben() getKontoStand()

überweisen(kto, betrag)

(9)

9: private int ktoNummer;

10: private String ktoInhaber;

11: private double ktoStand;

12: /**

13: * Konstruktor für Objekte der Klasse 'Konto' 14: *

15: * @param ktoNr Parameter für Kontonummer 16: * @param ktoInh Parameter für Kontoinhaber 17: */

18: public Konto(int ktoNr, String ktoInh) 19: { // Initialisieren der Datenfelder 20: ktoNummer = ktoNr;

21: ktoStand = 0;

22: ktoInhaber = ktoInh;

23: } 24:

25: /**

26: * Auslesen des Kontostands 27: *

28: * @return Wert des Kontostands 29: */

30: public double getKontoStand() 31: {

32: return ktoStand;

33: } 34:

35: /**

36: * Einzahlung vornehmen 37: *

38: * @param betrag Betrag der Einzahlung 39: */

40: public void einzahlen(double betrag) 41: {

42: ktoStand = ktoStand + betrag;

43: } 44:

45: /**

46: * Auszahlung vornehmen, falls Kontostand ausreichend 47: *

48: * @param betr Betrag der Auszahlung 49: */

50: public void auszahlen(double betr) 51: {

52: if (ktoStand >= betr) 53: einzahlen(-betr);

54: else // Meldung ausgeben, wenn Konto nicht gedeckt:

55: System.out.println("Das Guthaben reicht nicht aus!");

56: } 57:

58: /**

59: * Überweisung auf ein anderes Konto vornehmen 60: *

61: * @param empfaenger Konto des Empfängers 62: * @param geldBetrag Betrag der Überweisung 63: */

64: public void ueberweisen(Konto empfaenger, double geldBetrag) 65: {

66: auszahlen(geldBetrag);

67: empfaenger.einzahlen(geldBetrag);

68: } 69: }

Auf die Eigenschaft private der Instanzvariablen dieser Klasse wird auf Seite 15 eingegangen.

Es werden jetzt die 5 Methoden der Klasse 'Konto' erläutert:

1. Die Methode Konto ist ein Konstruktor, denn sie heißt genauso wie die Klasse. Sie trägt die als Parameter übergebenen Werte in die Datenfelder der jeweiligen Instanz ein.

(10)

2. Mit der Methode getKontoStand wird der aktuelle Kontostand ausgelesen.

3. Die Methode einzahlen hat keinen Rückgabewert, deshalb muss sie mit dem reservierten Wort void deklariert werden.

Beim Einzahlen eines Betrages wird der Kontostand um diesen Betrag erhöht. Bei der Schreibweise ktoStand = ktoStand + betrag muss man sich klar machen, dass es sich nicht um eine Gleichung handelt, sondern um eine Wertzuweisung: Zuerst wird der Wert von ktoStand + betrag ermittelt, dann wird dieser wieder dem Datenfeld ktoStand

zugewiesen.

Die Schreibweise ist professionellen Programmierern noch zu umständlich, deshalb ist auch die kürzere – aber besonders für den Anfänger erheblich schwerer lesbare – Schreibweise zugelassen, die dasselbe bewirkt: ktoStand += betrag

4. Das Auszahlen entspricht dem Einzahlen eines negativen Betrags, deshalb kann man die Methode zum Einzahlen verwenden. Hier im Beispiel wurde einmal angenommen, dass man das Konto nicht überziehen darf; falls man mehr abheben möchte als der Kontostand beträgt, wird eine entsprechende Meldung ausgegeben. Der Vergleichsoperator >= steht für größer oder gleich. Die weiteren sind <= für kleiner oder gleich und == für gleich (s. S. 13).

5. Die interessanteste Methode ist hier die zum Überweisen. Beim Überweisen wird der angegebene Betrag vom Konto abgehoben und beim angegebenen Konto(-Objekt) eingezahlt. Das Überweisen eines negativen Betrags ist nicht verhindert, woraus sich natürlich ein Auftrag zur Programm-Verbesserung ergibt! Die Syntax für die if-Anweisung kann der Methode auszahlen entnommen werden.

Hinweis zum Ausführen des Konstruktors: Der Kontoinhaber muss mit Anführungszeichen ("Meier") eingegeben werden! Probieren Sie das Überweisen aus, nachdem mindestens zwei Konten erzeugt worden sind und auf das Absender-Konto ein (positiver) Betrag eingezahlt wurde!

Als Parameter muss hier der Name des Konto-Objekts für das Empfängerkonto eingegeben werden, dies kann auch mit Mausklick auf das Objektsymbol erfolgen.

Fragen und Aufgaben zum Text

8. Wie verfährt ein Konto im dargestellten Quelltext bei einer Überweisung, wenn die Deckung nicht ausreicht? Testen Sie es, überprüfen Sie die Kontostände!

9. Steht in der Methode ueberweisen die Variable empfaenger für den Inhaber des Empfängerkontos oder für die Konto-Instanz des Empfängerkontos? Begründen Sie!

Erstellen einer vollständigen Übersicht zur Klasse 'Konto'

Wir wählen den Menüpunkt Werkzeuge- Dokumentation erzeugen. Dieser Menüpunkt erstellt eine html-Seite (Text-Format für Web-

Seiten) und zeigt sie im Standard- Browser an (es dauert vielleicht ein Weilchen). Auf dieser html-Seite ist alles beschrieben, was als public

deklariert ist – die als private

deklarierten Datenfelder erscheinen nicht. Wer unsere Klasse 'Konto' ver- wenden will, muss nicht wissen, ob wir die intern verwendete Variable für die Kontonummer kontoNummer oder ktoNr genannt haben, weil er darauf nicht zuzugreifen braucht (s. auch S.

15).

(11)

Wenn Programmierer Java-Klassen austauschen oder weitergeben, geben sie in der Regel auch die Dokumentation mit. Die Klassen können als Quelltext (Datei mit der Extension „.java“) oder als compilierte Klasse (Extension „.class“) weitergegeben werden. Sie finden diese Dateien, wenn Sie mit dem Windows-Explorer den Ordner aufsuchen, in dem Sie Ihr Projekt gespeichert haben.

Die Dokumentation zeigt Ihnen außer den Bezeichnungen der öffentlichen Methoden auch die Bedeutung der Kommentare, die Sie mit '/**' eingeleitet haben: Sie finden nicht nur die Kom- mentare zu den Methoden in der Method Summary wieder, sondern bei der differenzierten Beschreibung der einzelnen Methoden (weiter unten) auch die Bedeutung der Parameter (siehe

@param) oder die Bedeutung des Rückgabewerts (siehe @return) der Methode getKontostand. Klicken Sie in der Constructor Summary auf den Klassenbezeicher 'String': Sie werden auf eine völlig gleichartig aufgebaute Webseite geführt, welche die Klasse 'String' beschreibt. Auf diesen Typ von Webseiten trifft man (fast) immer, wenn man Erklärung zu JAVA-Klassen sucht.

Kommentare, die dagegen mit // eingeleitet wurden (einzeilige Kommentare), sind als Notizen aufzufassen, die der Programmierer für sich selbst (oder einen Leser des Quelltextes) angefertigt hat. Das gilt auch für die mehrzeiligen Kommentare, die zwischen '/*' und '*/' stehen.

Fragen und Aufgaben zum Text

10. Untersuchen Sie, wie sich die Dokumentation der Klasse ändert, wenn Sie vor einem der Datenfelder das Schlüsselwort private durch public ersetzen! (Siehe auch Seite 15.) 11. Untersuchen Sie, wie sich die Dokumentation der Klasse ändert, wenn Sie vor einem der

Datenfelder das Schlüsselwort private (bzw. public) entfernen (machen Sie dies anschließend für die weitere Verwendung des Projekts rückgängig!). Testen Sie auch den Shortcut Strg-j.

Dieses Beispiel hat gezeigt, dass Instanzen auch auf Methoden anderer Instanzen zugreifen können:

Beim Überweisen ruft das überweisende Konto die Methode einzahlen des empfangenden Kontos auf. Die Syntax dafür erfordert die Angabe des Objekts, dessen Methode aufgerufen werden soll, sowie den Namen der Methode – als Trennzeichen steht dazwischen ein Punkt.

Es mag als unbefriedigend erscheinen, dass beim Überweisen von einem Konto auf ein anderes jeweils der Name des Kontos eingegeben werden muss, und dass es hier nicht über die Eingabe der Kontonummer geht. Die Ursache liegt darin, dass es kein „übergeordnetes“ Objekt gibt, das die Fähigkeit besitzt, aus der Kontonummer zu ermitteln, welche Kontoinstanz dazu gehört. Wenn man bei einer Überweisung eine Kontonummer als Parameter übergeben möchte, müssten alle vorhan- denen Kontoinstanzen daraufhin durchsucht werden, ob sie die betreffende Kontonummer besitzen.

Wenn das Konto nicht gefunden wird, muss die Überweisung abgelehnt werden.

Dieser anspruchsvollen Aufgabe widmet sich das folgende Kapitel.

3. Drittes Projekt: Bank_2

Legen Sie ein neues Projekt mit dem Namen 'Bank_2' an. Dieses Projekt verwendet wieder eine Klasse 'Konto', dessen Quelltext fast vollständig mit dem des vorigen Projekts übereinstimmen wird. Klicken Sie nicht auf „Neue Klasse“, sondern wählen Sie im Menü „Bearbeiten / Klasse aus Datei hinzufügen ...“! So können Sie aus Bank_1 die Klasse „Konto“ ins Projekt Bank_2 kopieren.

Bearbeiten Sie jetzt in 2 Punkten den Quelltext dieser Klasse:

Als erstes löschen Sie die Methode ueberweisen der Klasse 'Konto' im Projekt Bank_2, denn Überweisungen wird die noch zu erstellende Klasse 'Bank' übernehmen.

Die Klasse 'Konto' benötigt aber noch eine kurze Methode getKontoNummer():

public int getKontoNummer() {

return ktoNummer;

}

Ergänzen Sie diese Methode, gern auch mit den Kommentaren für die Dokumentation!

(12)

Anschließend erstellen wir eine weitere Klasse in diesem Projekt mit dem Namen 'Bank' – dies wird damit unser erstes Projekt, in dem wir zwei Klassen definieren.

Die Konten, die im Bankmodell verwaltet werden sollen, müssen in irgendeiner Form gespeichert werden. JAVA stellt dafür die Klasse ArrayList zur Verfügung. Instanzen dieser Klasse sind Listen-Objekte, sie besitzen Methoden zum Verwalten der Listenelemente. Die wichtigste ist die zum Hinzufügen. Natürlich kann eine solche Liste eingetragene Elemente auch wieder löschen, eine „Kontoauflösung“ ist aber hier bei unserem Bankmodell nicht vorgesehen. Damit solche Listen-Objekte vielseitig sind, verwalten sie nur Zeiger auf die eingetragenen Elemente, aber keine Information darüber, von welchem Typ die eingetragenen Elemente sind. Die Liste merkt

sich also in unserem Beispiel nicht, ob ein Konto oder ein Quadrat eingetragen ist – die Konsequenzen zeigen sich, wenn man ein Element aus der Liste verwenden will (s.u.).

Der Quelltext der Klasse 'Bank' wird nun in Abschnitten erläutert:

1: import java.util.*; // macht ArrayList verfügbar!

2: /**

3: * Die Klasse Bank kann in einer Liste mehrere Konten verwalten, 4: * zwischen denen Überweisungen ausgeführt werden können.

5: *

6: * @author B.Spier 7: * @version 17.11.09 8: */

9: public class Bank 10: {

11: // einzige Instanzvariable 12: private ArrayList kontoListe;

13:

14: /**

15: * Konstruktor für Objekte der Klasse Bank 16: */

17: public Bank() 18: {

19: // Instanzvariable initialisieren 20: kontoListe = new ArrayList();

21: }

Da ArrayList nicht ein gewöhnlicher Typ wie z.B. int ist, sondern eine Klasse, muss von dieser Klasse erst eine Instanz (kontoListe) erzeugt werden, bevor sie verwendet werden kann. Das geschieht mit der Zeile 20 im Konstruktor für das Bankobjekt: Hier wird der Konstruktor von

ArrayList aufgerufen. Diese Syntax (new ...) haben Sie vielleicht auch schon bei der Erzeugung der Quadrate oder Konten „von Hand“ bei BlueJ bemerkt.

22: /**

23: * Einrichten eines neuen Kontos:

24: * Es ist kein Parameter für den Inhaber vorgesehen, weil das Testen 25: * des Programms dann einfacher ist. Alle Konten gehören "Meier"!

26: * @param kontoNr für die Kontonummer 27: */

28: public void neuesKonto(int kontoNr) 29: {

30: Konto neuKto; // Variable neuKto vom Typ Konto 31: neuKto = new Konto(kontoNr,"Meier"); // Konto-Objekt erzeugen 32: kontoListe.add(neuKto); // Konto in die Liste eintragen

33: }

Modell der Klasse 'Bank':

Klasse Bank Felder:

Liste der Konten Konstruktor

Bank() Methoden

neuesKonto() einzahlen() abheben() getKontoStand() ueberweisen()

(13)

Anders als im vorigen Beispiel werden neue Konten jetzt nicht mehr durch BlueJ nach Rechtsklick auf das Klassensymbol für 'Konto' erzeugt, sondern durch die Methode neuesKonto eines Bankobjekts. Wir müssen also erst ein Bankobjekt erzeugen, dann können wir nach Rechtsklick auf das Objektsymbol dessen Methode neuesKonto() aufrufen, die den Konstruktor der Klasse 'Konto' verwendet. Das neu erzeugte Konto – besser eine Referenz darauf (auch „Zeiger“ genannt) – wird dann mit add in die Liste eingetragen. Eine Bankinstanz verwaltet so jedes erzeugte Konto in seiner Liste der Konten.

35: /**

36: * Suchen des Konto-Objekts an Hand seiner Kontonummer 37: *

38: * @param num für die Kontonummer

39: * @return Referenz auf das (hoffentlich!) gefundene Konto(-Objekt) 40: */

41: private Konto findByNumber(int num) 42: {

43: int i; // Zähler für die Schleife, Referenzen

44: Konto einKto, dasKto; // Zeiger für laufendes bzw. gefundenes Kto.

45: // (in der Schleife benötigte Variablen) 46: i = 0; // Initialisierung für die Schleife

47: dasKto = null; // Null-Zeiger, steht für ungültiges Konto 48: while (i < kontoListe.size()) // Schleifenkopf

49: { // Alle Konten in der Liste werden geprüft.

50: einKto = (Konto) kontoListe.get(i); // Ein Konto aus der Liste 51: if (einKto.getKontoNummer() == num) // KtoNr. prüfen

52: dasKto = einKto; // hier: Konto gefunden!

53: i++; // entspricht i = i + 1;

54: }

55: if (dasKto == null)

56: System.out.println("ungültige Kontonummer!");

57: return dasKto; // Referenz auf das gefundene Konto (oder null) 58: }

Mit Hilfe der Methode findByNumber kann das Bankobjekt alle Konten, die in die Liste eingetragen sind, nach der Kontonummer durchsuchen. Wir verwenden hier eine while-Schleife, weil dies die einfachste Schleifenprogrammierung ist; die Kommentare erklären schon fast alles:

Wenn in der Liste z.B. 5 Konten eingetragen sind, wird die Schleife 5-mal durchlaufen, wobei i

nacheinander die Werte 0, 1, …, 4 annimmt. Die Schleife wird auch dann 5 mal durchlaufen, wenn das gesuchte Konto schon früher gefunden wurde – das ist zwar keine optimale Programmierung, erlaubt aber eine leicht verständliche Form unserer ersten Schleife (mehr zu while s.S. 39).

Zeile 50: Weil die Liste mit get(i) nur einen untypisierten Zeiger auf das Listenelement am Platz i

zurück gibt, muss dieser vor der Zuweisung an die Variable einKonto eine Typumwandlung erfahren. Das geschieht durch das vorangestellte (Konto) – der Fachmann spricht dabei von einem

„Cast-Operator“. Eine unpassende Typumwandlung kann schlimme Fehler verursachen, deshalb gibt es beim Übersetzen eine Warnmeldung! (Ergänzende Information siehe Anhang, Seite 41) Die Methoden einzahlen und abheben verwenden diese Methode findByNumber:

60: /**

61: * Einzahlen auf ein Konto unter Angabe der Parameter 62: *

63: * @param kontoNr für die Kontonummer 64: * @param betrag für den Geldbetrag 65: */

66: public void einzahlen(int kontoNr, double betrag) 67: {

68: Konto dasKonto;

69: dasKonto = findByNumber(kontoNr);

70: if (dasKonto != null) dasKonto.einzahlen(betrag);

71: }

(14)

Zeile 70 prüft, ob überhaupt eine Konto mit der angegebenen Nummer gefunden wurde: In JAVA steht das Ausrufezeichen für die Negation, != heißt also „ungleich“. Die if-Anweisung ist hier ohne

else verwendet worden. Bei ungültiger Kontonummer wurde ein Hinweis bereits von

findByNumber ausgegeben. Weil die Anweisung in Zeile 70 bzw. 83 so kurz ist, wird auf den sonst bei if-Anweisungen üblichen Zeilenumbruch verzichtet.

73: /**

74: * Abheben von einem Konto unter Angabe der Parameter 75: *

76: * @param kontoNr für die Kontonummer 77: * @param betrag für den Geldbetrag 78: */

79: public void abheben(int kontoNr, double betrag) 80: {

81: Konto dasKonto;

82: dasKonto = findByNumber(kontoNr);

83: if (dasKonto != null) dasKonto.auszahlen(betrag);

84: }

Abrufen des Kontostands (können Sie eine Prüfung auf gültige Kontonummer ergänzen?):

86: /**

87: * Abrufen des Kontostands unter Angabe der Kontonummer 88: *

89: * @param kontoNr für die Kontonummer 90: * @return Kontostand

91: */

92: public double kontostandAbrufen(int kontoNr) 93: {

94: Konto dasKonto = findByNumber(kontoNr);

95: return dasKonto.getKontoStand();

96: }

Haben Sie bemerkt, dass die Deklaration einer Variablen (dasKonto) und die Zuweisung an diese in einem einzigen Schritt erfolgen kann? Hier wird der Zeiger auf das gefundene Konto zugewiesen.

Nun zur Methode zum Überweisen von einem Konto auf ein anderes:

98: /**

99: * Überweisen unter Angabe der Parameter 100: *

101: * @param ktoNrA Konto des Absenders 102: * @param ktoNrB Konto des Empfängers 103: * @param betrag Betrag der Überweisung 104: */

105: public void ueberweisen(int ktoNrA, int ktoNrB, double betrag) 106: {

107: Konto empf, absd; // Konto-Objekte 108: absd = findByNumber(ktoNrA);

109: empf = findByNumber(ktoNrB);

110: if ((absd != null) & (empf != null)) 111: {

112: absd.auszahlen(betrag);

113: empf.einzahlen(betrag);

114: } 115: } 116: }

Hier muss die Gültigkeit beider Kontonummern geprüft werden. Nur wenn Absender-Konto absd

und Empfänger-Konto empf gültig sind, wird die Überweisung ausgeführt. Die logische UND- Verknüpfung wird in JAVA durch das &-Zeichen dargestellt. Da im WENN-Fall zwei Anweisungen stehen, sind geschweifte Klammern zur Kennzeichnung von Anfang und Ende des Blocks erforderlich. Dasselbe gilt auch für den SONST-Fall, wenn er aus mehreren Anweisungen besteht.

(15)

(Die Klammern dürfen selbstverständlich auch gesetzt werden, wenn sie nur eine einzige Anwei- sung einschließen).

Wenn sich der Quelltext für die Klasse 'Bank' fehlerfrei übersetzen ließ, können wir jetzt unser Bankinstitut eröffnen und Kundenkonten einrichten, um

die von uns programmierten Klassen und deren Instanzen zu testen! Also: Bankinstanz mit Rechtsklick erstellen, Bank-Namen wählen (z.B. "JGiro", "DieBank"

o.ä.) und dann in dieser Bank mindestens 2 Konten einrichten. Nach einer Einzahlung sollte dann auch eine Überweisung möglich sein.

Die Klasse 'Konto' wird jetzt nicht mehr von uns, sondern nur von dem Bank-Objekt benutzt. Diese Beziehung „Bank verwendet Konto“ (allgemein

„<Klasse> verwendet <AndereKlasse>“) stellt BlueJ durch einen gestrichelten Pfeil in der Projektübersicht dar.

Fragen und Aufgaben zum Text

12. Ergänzen Sie in einem der Bank-Projekte eine Methode, die zur Kontonummer den Namen des Kontoinhabers zurück gibt.

13. Ein Objekt A soll die Methode tuIrgendWas() eines Objekts B aufrufen. Wie ist der Aufruf zu schreiben?

14. Im Projekt Bank seien zwei Instanzen erzeugt: HASPA und DEUTSCHE_BANK. Mit beiden Instanzen wurden mehrere Konten erzeugt. Welche Überweisungen sind möglich?

Informationen zu private und public

Bisher wurden alle Datenfelder als private deklariert. Das ist üblich, wenn keine fremde Instanz direkten Zugriff auf den Wert einer solchen Variablen zu haben braucht.

Stellen wir uns vor, von der Klasse 'Konto' haben wir keinen eigenen Quelltext, sondern nur die compilierte Klassendatei und die Dokumentation. Wir erstellen eine Klasse 'Bank', welche Instanzen der Klasse 'Konto' verwalten soll. Dadurch, dass ktoStand als private deklariert ist, kann nur über öffentliche Methoden (getKontoStand, auszahlen, einzahlen) auf den Kontostand zugegriffen werden. Der Programmierer der Klasse 'Konto' könnte diese Methoden so erweitern, dass erst eine Geheimnummer eingegeben werden muss, bevor der Kontostand ausgelesen oder eine Auszahlung/Überweisung vorgenommen werden kann. Methoden, die den Kontostand ändern, könnten auch jeweils einen Text ausgeben, der einem Kontoauszugs-Eintrag entspricht. Wäre

ktoStand jetzt public, so könnten wir in der Klasse 'Bank' die folgende Methode programmieren, die eine Berechtigungsprüfung umgeht, indem sie auf den Kontostand direkt zugreift:

public void ueberweisen(int ktoNrA, int ktoNrB, double betrag) {

Konto empf, absd; // Konto-Objekte absd = findByNumber(ktoNrA);

empf = findByNumber(ktoNrB);

if ((absd != null) & (empf != null)) {

absd.ktoStand -= betrag; // Kontostand verringern empf.ktoStand += betrag; // Kontostand erhöhen }

}

Nicht nur Variablen, auch Methoden können private oder public sein. Unsere Klasse Bank benötigt die Methode findByNumber, die wir aber beim simulierten Zahlungsverkehr mit der Maus im BlueJ-Fenster nie aufzurufen brauchen und deshalb als private deklariert haben.

(16)

Hätten wir sie als public deklariert, wäre die Auswahl der möglichen Methoden beim Rechtsklick auf ein Bankinstanzsymbol um eine unnötige Zeile unübersichtlicher geworden, wie die Abbildung zeigt.

Grundsätzlich sollten also nur die Me- thoden und Datenfelder öffentlich sein, auf die der Zugriff „von außen“

tatsächlich benötigt wird.

4. Viertes Projekt:

Fahrkartenautomat

Mit diesem Projekt testen Sie sich, wie weit Sie eigenständig (nach wenigen Vorgaben) programmieren können. Fast alles, was Sie benötigen, wurde in den bisherigen Kapiteln genannt:

• Namen für das Projekt festlegen (also einen Ordner einrichten),

• neue Klasse erzeugen (wieder einen Namen überlegen),

• private Datenfelder deklarieren, diese mit dem Konstruktor initialisieren,

• weitere Methoden programmieren (siehe folgende Punkte 1, 2, 3, 5).

Orientieren Sie sich dabei an den bisher erstellten Programmen!

Unser virtueller Fahrkartenautomat soll folgendes können:

1. Der Anwender muss einen Fahrpreis für die gewünschte Fahrkarte eingeben können (Festlegung des zu zahlenden Betrags, z.B. 4.3 für 4,30€), die Klasse benötigt dafür eine sinnvoll benannte Methode. Ein Datenfeld fahrPreis vom Typ double muss dann den gewünschten Fahrpreis speichern. Zum Testen des Automaten ist es zweckmäßig, bereits im Konstruktor den Fahrpreis mit z.B. 3.8 zu initialisieren – dann muss man nicht bei jedem Neustart erst einen Fahrpreis eingeben.

2. Der Anwender muss nach der Festlegung des Fahrpreises „Geld einwerfen“ können (z.B.

mehrmals 1€ oder 0,50€ o.ä.), eine Prüfung auf tatsächlich möglichen Münzwert entfällt. Die Klasse benötigt im Prinzip also eine Methode einzahlen(betrag) wie im vorigen Projekt.

Ein weiteres Datenfeld einwurf vom Typ double muss den bereits gezahlten Betrag speichern.

3. Eine Methode druckeFahrkarte soll einen von der bisherigen Zahlung abhängigen Text aus- geben: Zuerst wird der gewählte Fahrpreis „ausgedruckt“, dann der bisher gezahlte Betrag.

Wenn dieser noch nicht reicht, wird der Fehlbetrag ausgegeben. Wurde genug gezahlt, ist der Kauf abgeschlossen, und die Höhe des Wechselgeldes wird ausgegeben. Außerdem muss der eingeworfenen Betrag auf 0 zurückgesetzt werden. Info zum „Drucken“:

System.out.println (print line) gibt eine Zeile, also Text mit an- schließendem Zeilenumbruch aus.

Neu ist hier: System.out.print

(ohne ln) gibt Text aus, ohne dass sich ein Zeilenumbruch anschließt. Sie können die beiden letzten Zeilen aber auch zu einer einzigen zusammenfassen:

System.out.println("Fahrkarte zu " + fahrPreis);

Mit + können Strings aneinander gehängt werden, in diesem Fall wandelt JAVA die Zahl

fahrPreis dazu in einen String um.

4. Diesen Punkt können Sie ergänzen, nachdem alles andere fehlerfrei läuft:

System.out.println("BlueJ-Bahngesellschaft");

System.out.print("Fahrkahrte zu "); // Text System.out.println(fahrPreis); // Wert ... (u.s.w.)

(17)

Die Klasse soll ein drittes Datenfeld gesamtEinnahmen besitzen, in dem die Einnahmen bei jedem Kauf eines Fahrscheins aufsummiert werden. Es genügt, dass dieses Datenfeld durch

„Inspizieren“ geprüft werden kann – oder möchten Sie eine Methode getGesamteinnahmen()

schreiben?

5. Optional können Sie den Fahrkartenautomaten verbessern, indem Sie eine Methode zum Abbrechen des Fahrkartenkaufs ergänzen. Sie sollte als Text die Rückzahlung des bisher eingeworfenen Betrags melden. Was muss sie sonst noch tun?

Die Abbildung zeigt ein mögliches Ergebnis des Projekts: Sie können den Namen des Projekts, den Namen der Klasse und den aktuell gewählten Namen für die Instanz dieser Klasse herauslesen.

Ein Fahrpreis wurde fest- gelegt, Geld wurde „einge- worfen“.

Das Bild zeigt das Fenster nach Aufruf der Methode

druckeFahrkarte.

Mit Sicherheit wird Ihr Ergebnis noch nicht so wie hier aussehen können, denn hier wurde die Ausgabe auf 2 Nachkommastellen und mit

Dezimalkomma formatiert. Diese Formatierung rundet zugleich, so dass Rechenfehler ausgeglichen werden. Es folgen hierzu weitere Informationen:

Wie entstehen Rechenfehler beim Computer?

Computer rechnen im Zweiersystem. Brüche wie 12 , 14 , 18 , 58 sind in diesem System abbrechende Dualbrüche. Brüche, deren Nenner jedoch keine Zweierpotenz sind, sind periodische Dualbrüche.

Der Grund ist der, den wir aus dem Dezimalsystem kennen: Wenn der Nenner sich nicht aus Potenzen von 2 oder 5 zusammensetzt, wird der Dezimalbruch periodisch. 2 und 5 sind Teiler der Basis 10, daher ist z.B. 253=532=10012=0,12 abbrechend. 114=0, 36 ist dagegen periodisch. Da die Basis 2 nur die 2 als echten Teiler hat, können im Zweiersystem nur Brüche wie die oben genannten abbrechend sein, 15 oder 101 sind in diesem System dagegen periodisch, also unendlich lang. Da der Computer aber Zahlen nur in wenigen Bytes speichert, muss er die Darstellung abbrechen.

Selbst wenn dabei richtig gerundet wird, entstehen Ungenauigkeiten. Die Ungenauigkeit zeigt sich beim Fahrkartenautomaten z.B. bei einem Fahrschein zu 3,80€, wenn 0,10€ bezahlt sind. Als Restbetrag werden 3,699999999999997€ berechnet! (Probieren Sie es aus!)

Zahlen formatieren

JAVA stellt verschiedene Methoden zum Formatieren von Zahlen zur Verfügung. In JAVA sind alle Methoden an Klassen gebunden, wir verwenden hier die Methode format der Klasse String.

String.format("Noch zu zahlen: %.2f €",(fahrPreis – einwurf))

liefert einen formatierten String für den Wert von (fahrPreis – einwurf), er enthält am Beginn den Text „Noch zu zahlen: “. Das %-Zeichen kennzeichnet das Einfügen aus nachfolgend angegebenen Parametern. „.2“ kennzeichnet die Genauigkeit von 2 Nachkommastellen, „f“ kennzeichnet die Umwandlung eines float- oder double-Werts (Fließkommazahl). Die weiteren Zeichen „“ folgenden dem eingefügten String, sodass das Ergebnis z.B. im Falle des Werts

(18)

0.1999999994 der String „Noch zu zahlen: 0,20 €“ wird, weil die Methode zugleich auch rundet.

Die Umwandlung des Dezimalpunkts in ein Komma erfolgt auf Grund der Spracheinstellung des Betriebssystems.

Die format-Methode der Klasse String ist sehr vielseitig, mit ihr können z.B. auch Datumswerte formatiert werden (siehe nachfolgendes Kapitel). Ein weiteres Beispiel für die Formatierung auf 2 Nachkommastellen:

System.out.println(String.format("Fahrkahrte zu %.2f €",fahrpreis));

Diese Art der Formatierung können Sie überall dort verwenden, wo ein Euro-Wert mit 2 Nachkommastellen ausgeben werden soll.

5. Fünftes Projekt: Person (Vererbung / GregorianCalendar)

Ein bedeutendes Merkmal objektorientierter Programmierung (und darum geht es bei JAVA) ist die Möglichkeit, bereits programmierte Klassen als Ausgangsbasis für weitere Klassen mit zusätzlichen Datenfeldern und Methoden zu verwenden. Die so von einer Basisklasse „abgeleiteten“ Klassen erben die Datenfelder und Methoden der Basisklasse, wodurch der Quelltext der neuen Klasse weniger umfangreich ist. Die Verwendung fertiger Basisklassen ist für den Programmierer eine deutliche Arbeitserleichterung.

Dieses Prinzip werden wir in Kapitel 6 nutzen, um mit Hilfe bereits in JAVA vorgegebener Klassen

„Applets“ (Anwendungen) zu programmieren, die in einem Browser ablaufen können.

Erzeugen Sie das neue Projekt mit dem Namen „Vererbung“. Erstellen Sie in diesem Projekt eine Klasse mit der Bezeichnung Person. Eine Person hat einen Vornamen, einen Nachnamen, ein Geburtsdatum. Außerdem soll

vermerkt werden können, ob die Person Informatiker ist oder nicht. Vor- und Nachname sind Strings, das Geburtsdatum müssen wir als Instanz der in JAVA vordefinierte Klasse

GregorianCalendar festlegen (die Bezeichnung bezieht sich auf den Gregorianischen Kalender, der seit dem 15.

Oktober 1582 regelt, welche Jahre Schaltjahre sind). Die Informatiker-Eigenschaft kann nur die Werte true oder false

annehmen, dieser Typ heißt

boolean. Wenn eine Person geboren wird, steht das Geburtsdatum fest – darum wird hier vorgeschlagen, dass der Konstruktor beim Erzeugen einer Instanz der Klasse Person

Tag, Monat und Jahr der Geburt erfragt.

(19)

Wenn wir jetzt eine Instanz erzeugen, müssen wir also Werte für t, m, j eingeben. Da

GregorianCalendar die Monate als Zahlen von 0 bis 11 verwaltet, muss die Eingabe für m um 1 vermindert werden!

Beim Inspizieren der Person werden Sie feststellen, dass Sie das Geburtsdatum nicht in der Form von Tag, Monat und Jahr auslesen können. Möchten Sie eine Methode getGeburtsdatum() schrei- ben, die dieses Datum als String zu- rückgibt? Dazu müssen Sie heraus- finden, wie aus der Instanz

geburtsDatum ein Datumsstring gewon- nen werden kann! Sie müssen jetzt keine Suchmaschine oder Foren bemühen, holen Sie sich mit BlueJ (siehe Abb.) die Hilfe über Klassenbibliotheken! Sie führt auf die Webseite

(Stand vom September 2014) http:// docs .oracle.com/javase/ 7 /docs/api/

Sie finden dann in der Beschreibung der Klasse String etwas weiter unten die Beschrei- bung der beiden format-Metho- den.

Klicken Sie wie in der Abbildung angedeutet auf „format“, von dort können Sie zu einer so umfang- reichen Beschreibung gelangen, wie ein „format string“ aussehen kann, dass Sie erleichtert sein dürften, einen Weg zur formatier- ten Ausgabe eines Datums auch im folgenden Absatz zu finden:

(20)

Die folgende Methode gibt das in geburtsDatum gespeicherte Datum formatiert als String zurück:

public String getGeburtsdatum() {

return String.format("%1$td.%1$tm.%1$tY", geburtsDatum);

}

Vielleicht gelingt es Ihnen ja, mit Hilfe der angegebenen Webseite das Datum auch so zu formatieren, dass zusätzlich noch der Wochentag ausgegeben wird (Aufgabe 22)!

Anmerkungen: Methoden, die Daten auslesen, beginnen üblicherweise mit get. Daran lehnt sich hier der Vorschlag für den Methodennamen zum Auslesen des Geburtsdatums an. Wenn Sie solche Sprachvermischungen vermeiden wollen, können Sie getDayOfBirth oder holeGeburtsdatum

verwenden. Ein Vorteil deutscher Wortanteile ist der, dass sofort erkennbar ist, ob vordefinierte oder eigene Bezeichner verwendet sind.

Zur Übung – und damit unsere „Person“ etwas mehr zu vererben hat (darum geht es ja in diesem Kapitel), folgen zunächst noch einige Aufgaben:

Fragen und Aufgaben zum Text

15. Wie ändert sich die formatierte Datumsausgabe, wenn Sie im format-String für das Jahr ein kleines „y“ verwenden?

16. Damit die Person einen Namen bekommt, wird eine Methode setName(String v, String n)

benötigt, mit der Vor- und Nachname festgelegt werden. Schreiben Sie diese.

17. Schreiben Sie eine Methode setInfomatikerYes(), die das Datenfeld informatiker auf

true setzt.

18. Schreiben Sie eine Methode setInfomatikerNo(), die informatiker auf false setzt.

19. Schreiben Sie eine Methode setInfomatiker(boolean x), die informatiker auf einen Wert setzt, den der Anwender eingibt.

20. Schreiben Sie eine Methode getGanzerName(), die die Kombination aus Vor- und Nachnamen als String zurück gibt.

21. Schreiben Sie eine Methode druckeGanzenNamen(), die mit System.out.println den vollständigen Namen auf das Konsolenfenster ausgibt. Diese Methode sollte getGanzerName

verwenden!

22. Schaffen Sie es, das Geburtsdatum einschließlich Wochentag auszugeben?

Berechnung des Alters einer Person

Wir ergänzen jetzt noch eine Methode, die das Alter der Person liefert. Dafür brauchen wir eine Instanz von GregorianCalender, die das aktuelle Datum enthält. Wir nennen sie heute und erhalten sie, indem wir den Konstruktor ohne Parameter aufrufen. Dann schließt sich die Berechnung des Alters an, die nicht ganz einfach ist, weil zunächst festgestellt werden muss, ob die Person im laufenden Jahr bereits Geburtstag hatte (oder gerade hat). Die Verwendung einer Hilfsvariablen hatteSchonGeburtstag macht den folgenden Quelltext (hoffentlich) leicht verständlich:

(21)

Vererbung

Jetzt sollen zwei weitere Klassen erstellt werden: Eine Klasse Schüler und eine Klasse Lehrer. Da Schüler und Lehrer natürlich Personen sind, sollen auch sie Namen und Geburtsdatum besitzen.

Zusätzlich sollen Schüler aber ein Datenfeld für ihre Schulklasse (z.B. "11c", also vom Typ String) besitzen. Lehrern geben wir keine Schulklasse, dafür aber zwei Unterrichtsfächer (weil das für die meisten Lehrer am Gymnasium zutrifft).

Natürlich könnte man den Quelltext von Person kopieren, um alles zu übernehmen, und man müsste nur die Klassenbezeichnung (Objektklasse, nicht Schulklasse – der Begriff „Klasse“ ist in diesem Abschnitt leider nicht eindeutig!) im Konstruktor anpassen. Für den Zugriff auf Unterrichtsfächer bzw. die Schulklasse wären noch wenige Methoden zu ergänzen. Dann hätten wir aber einen großen Teil des Quelltextes 3 mal zu verwalten. Ein Fehler in der Berechnung des Alters müsste in 3 Textdateien korrigiert werden. Um solche Nachteile zu vermeiden, wurde die Möglichkeit geschaffen, von vorhandenen Klassen erweiterte Klassen abzuleiten. Die abgeleiteten Klassen erben dann alle Eigenschaften und Methoden der Vorgängerklasse.

Zunächst erstellen wir in unserem Projekt eine neue Klasse mit der Bezeichnung „Schüler“ (oder „Schueler“) und eine weitere mit der Bezeichnung „Lehrer“.

Es gibt bei BlueJ zwei Verfahren, um diese Klassen als Erweiterungen von Person zu deklariereren.

Methode 1:

Im BlueJ-Fenster wählen wir mit der Maus den Pfeil mit durchgezogener Linie aus und ziehen damit einen Pfeil von Lehrer zu Person.

Methode 2: Wir fügen in der Klasse Schüler die zwei Wörter extends Person ein (s. Abb.).

public class Schüler extends Person {

.... <u.s.w.> ...

} public int getAlter()

{

boolean hatteSchonGeburtstag = false; // wird nach Prüfung evt. true GregorianCalendar heute = new GregorianCalendar(); // Kalenderobjekt für // heutiges Datum if (heute.get(Calendar.MONTH) > geburtsDatum.get(Calendar.MONTH)) // Person hatte in diesem Jahr

hatteSchonGeburtstag = true; // schon Geburtstag. Weitere Prüfung else // bei gleichem Monat:

if (heute.get(Calendar.MONTH) == geburtsDatum.get(Calendar.MONTH) & heute.get(Calendar.DAY_OF_MONTH) >=

geburtsDatum.get(Calendar.DAY_OF_MONTH)) // Tag vergleichen hatteSchonGeburtstag = true;

if (hatteSchonGeburtstag)

return heute.get(Calendar.YEAR) - geburtsDatum.get(Calendar.YEAR);

else

return heute.get(Calendar.YEAR) - geburtsDatum.get(Calendar.YEAR) - 1;

}

(22)

Die Konstruktoren der neuen Klassen sollen nun so überarbeitet werden, dass sie Lehrer- bzw. Schülerinstanzen mit Ge- burtsdatum erzeugen:

Ein Konstruktor der abgeleiteten Klasse muss einen Konstruktor der Vorgänger- klasse durch Verwendung des Schlüssel- worts super aufrufen. Für die Klasse

Lehrer sind hier als Beispiel zwei Kon- struktoren angegeben.

Ganz ähnlich gestalten wir den Quelltext für die Klasse Schüler.

Wenn Sie jetzt Instanzen von Lehrer und

Schüler erzeugen, stehen diesen alle Methoden von Person zur Verfügung.

Fragen und Aufgaben zum Text:

23. Ergänzen Sie für die Klasse Schüler

eine Methode zum Setzen der Schul- klasse!

24. Erzeugen Sie Instanzen von Person,

Schüler, Lehrer und testen Sie deren Methoden, so dass z.B.

beim Inspizieren von

schüler1 die abgebildete Situation entsteht!

Überschreiben

Wenn eine Klasse eine Vorgängerklasse erweitert, so erbt sie deren Metho- den. Manchmal ist es sinnvoll, eine geerbte Me- thode für die erweiterte Klasse speziell anzu- passen. Man könnte zum Beispiel annehmen, dass ein Lehrer auch das Fach Informatik unterrichtet, wenn er Informatiker ist.

/**

* Beschreibung der Klasse Schüler.

*

* @author B.Spier * @version Jan. 2014 */

public class Schüler extends Person {

String klasse;

/**

* Konstruktor für Schüler */

public Schüler(int t, int m, int j) {

super(t, m, j);

klasse = "";

} }

/**

* Beschreibung der Klasse Lehrer.

*

* @author B. Spier * @version Jan. 2010 */

public class Lehrer extends Person {

private String fach1, fach2;

/**

* Konstruktoren für Lehrer */

public Lehrer(int t, int m, int j) {

super(t, m, j);

}

public Lehrer(int t, int m, int j, String f1, String f2) {

super(t, m, j);

fach1 = f1;

fach2 = f2;

} }

(23)

Es soll jetzt die Methode setInfomatikerYes()

speziell für Lehrer erweitert werden, so dass dabei

fach2 auf „Informatik“ gesetzt wird.

Weil informatiker in Person als private deklariert ist, verwenden wir die geerbte öffentliche Methode

setInformatikerYes() von Person. Nun kann aber

public void setInformatikerYes() {

setInformatikerYes();

fach2 = "Informatik";

}

nicht funktionieren, weil jetzt die Methode des Lehrers immer wieder sich selbst aufruft, anstatt auf die geerbte Methode zuzugreifen!

Die Lösung ist das Schlüsselwort super, das wir schon beim Aufruf des geerbten Konstruktors kennen gelernt haben (s. rechts).

Als Nachweis, das dies wirklich funktioniert, ergänzen wir einige Zeilen in der Klasse Schüler:

public class Schüler extends Person {

String klasse;

Person einLehrer; // <--- ERGÄNZUNG public Schüler(int ta, int mo, int ja)

{

super(ta, mo, ja);

klasse = "";

einLehrer = new Lehrer(2,5,1961); // <--- ERGÄNZUNG einLehrer.setInformatikerYes(); // <--- ERGÄNZUNG }

//...

}

Erzeugen Sie jetzt eine Instanz von „Schüler“. Inspizieren Sie diesen Schüler, inspizieren Sie dann dessen Objekt einLehrer!

Dass einLehrer einem Datenfeld vom Typ Person zugewiesen wurde, hat hier keine Auswirkung, es hätte ebenso gut auch ein Feld vom Typ Lehrer verwendet werden können.

Methode in der Basisklasse „Person“

(Lösung von Aufgabe 18):

public void setInformatikerYes() {

informatiker = true;

}

Methode, die in der Klasse „Lehrer“ ergänzt wird, und damit die geerbte überschreibt:

public void setInformatikerYes() {

super.setInformatikerYes();

fach2 = "Informatik"

}

Referenzen

ÄHNLICHE DOKUMENTE

Die Kosten für Zulassung, Transport und Überführung erfahren Sie von Ihrem MINI Partner.. Angebot gültig für Gewerbetreibende und juristische

Dies spiegelt sich auch in den Themen wider, die wir uns wäh- rend unserer Mitgliedschaft im Sicher- heitsrat vorgenommen haben: Lösungen für Konflikte wie in Syrien und Libyen,

den kann, muss die NATO zudem als Plattform für eine Zusammenarbeit mit Partnern jenseits der Allianz

Schon jetzt erwächst damit für Deutschland mehr Verantwortung, sich nicht nur bilateral, sondern auch in der europäischen Afrika- politik stärker gestaltend

[r]

private int zahl1; // Attribut public Dings() {} // Konstruktor public void quadratBerechnen(). int ergebnis = this.zahl1

[r]

Aber der vor- handene politische Druck wird möglicherweise dazu führen, dass wir tatsächlich in drei bis vier Monaten ein völlig reformiertes Gebilde internationaler Normen