Leseprobe

Werbung
Ein erster Blick auf ein Java-Programm
14
Sparkonto
kontonummer: Zeichenkette
kontoinhaber: Zeichenkette
kontostand: Ganzzahl
speichern kontonummer
speichern kontoinhaber
speichern kontostand
ausgabe kontonummer
ausgabe kontoinhaber
ausgabe kontostand
bearbeiten kontobewegung
Klassenname
Attribute mit Datentyp
Methoden
Bei der objektorientierten Programmentwicklung ist es üblich, die Klasse in einem
UML-Klassen-Diagramm zu beschreiben. UML steht für Unified Modeling Language.
Im oberen Teil des Diagramms steht der Name der Klasse. Darunter werden die Attribute notiert. Im unteren Teil werden die Methoden aufgeführt.
In der Bankpraxis weist ein Sparkonto noch weitere Attribute und Methoden auf. Zur
Erklärung, was eine Klasse ist und wie sie in Java umgesetzt wird, mag die obige Festlegung reichen.
1.2.2
Umsetzung in eine Java-Klasse
Das obige UML-Klassendiagramm lässt sich relativ leicht in eine Java-Klasse umsetzen.
Klasse Sparkonto
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]
[18]
[19]
[20]
0804_01.indb 14
public class Sparkonto
{
private String kontonummer;
private String kontoinhaber;
private int kontostand;
public Sparkonto() {
}
public void setKontonummer (String ktonr) {
kontonummer = ktonr;
}
public void setKontoinhaber (String sparer) {
kontoinhaber = sparer;
}
public void setKontoStand (int betrag) {
kontostand = betrag;
}
public String getKontonummer() {
return kontonummer;
}
// Konstruktor
27.03.2012 11:19:59
28
Programmierumgebung
kann der Compiler das Maschinenprogramm erzeugen. Dieses Programm muss dann der
Programmierer auf logische Richtigkeit testen.
Aus der Abbildung wird zum einen deutlich, dass ein Programm nicht „so mal eben“
entwickelt werden kann. Zum anderen deuten die Rückbezüge der Korrekturpfeile an,
dass der Quellcode wie auch der Klassenentwurf oftmals korrigiert werden müssen, bis
das Programm ordnungsgemäß arbeitet.
Für die „komfortable“ Eingabe und Compilierung des Quellcodes ist eine integrierte
Entwicklungsumgebung unabdingbar. Sie fordert die erforderlichen Systeminformationen vom Programmierer an und erleichtert ihm so die Arbeit.
Zur Eingabe eines neuen Programms legen Sie zunächst ein Projekt an. Darunter versteht BlueJ ein Verzeichnis, in das später alle Dateien, die zu dem Projekt gehören, gespeichert werden. Im vorliegenden Fall wurde im Hauptverzeichnis C: das Unterverzeichnis javalernen angelegt. Als Projektnamen wurden die Kapitelnummern, zum
Beispiel Kapitel2 oder AufgabenKapitel2 gewählt.
Um ein Projekt anzulegen klicken Sie auf Projekt/Neues Projekt. In dem Dialogfenster
Neues Projekt legen Sie den Ordner sowie den Projektnamen fest.
Anschließend klicken Sie die Schaltfläche Neue Klasse und geben in dem Dialogfenster
den Namen der Klasse ein, hier zum Beispiel Sparkonto.
0804_01.indb 28
27.03.2012 11:20:02
Programmierumgebung
38
Sie sehen, die Eingabe wurde korrekt übernommen. Bei den beiden String-Variablen
wird null angezeigt, da noch nichts eingegeben wurde. Der Zustand ist noch undefiniert.
Die Angabe null darf nicht verwechselt werden mit der Zahl 0.
Schließen Sie das Inspektionsfenster und rufen als nächstes die Methode kontobewegung auf. Dort geben Sie in das Dialogfenster zum Beispiel den Betrag 444 ein. Das
Ergebnis können Sie sich mittels der Methode getKontoStand() anzeigen lassen.
Sie sehen, dass die Methode korrekt arbeitet.
2.6.2
Gesamttest
Auch wenn ein Programm ohne Fehlermeldung läuft und „richtige“ Ergebnisse anzeigt,
kann es aufgrund einer falschen Befehlsreihenfolge oder einer nicht korrekten Anweisung fehlerhaft sein. Um bei mathematischen Problemstellungen die logische Korrektheit zu überprüfen, empfiehlt es sich, vor dem Programmtest Zahlenbeispiele „manuell“
durchzurechnen. Bei anschließenden Programmläufen werden die Testwerte in den
Rechner eingegeben. Stimmen jeweils die Ergebnisse überein, kann man im Allgemeinen davon ausgehen, dass das Programm in Ordnung ist.
Die Suche nach logischen Fehlern kann sehr mühselig und zeitraubend sein. Hier hilft
BlueJ mit einem Debugger. Unter einem Debugger versteht man ein Programm, das zur
Diagnose eines Programms oder auch zur Fehlersuche eingesetzt wird. In dem Wort
steckt der Begriff bug, der eigentlich im Englischen Wanze bedeutet und als Synonym
für einen Fehler in einem technischen System gebraucht wird. Mit Hilfe eines Debuggers kann der Programmierer das Programm schrittweise durchlaufen und den Inhalt
von Variablen prüfen.
Zum Testen eines Programms aktivieren Sie den Debugger im Menü Ansicht oder mit
Hilfe der Tastenkombination <Strg><D>. Anschließend setzen Sie im Quellcode der
main-Methode einen Haltepunkt, hier am besten vor die Anweisung, in der das Objekt
der Klasse Sparkonto erzeugt wird. Dazu klicken Sie in die Vorspalte.
0804_01.indb 38
27.03.2012 11:20:04
Elemente eines Java-Programms
61
Da in Kontofuehrung2UI die Vereinbarung in der Methode run() erfolgt, ist die Objektvariable einsKonto nur zur Laufzeit dieser Methode gültig. Außerhalb existiert sie nicht.
Die Objektvariable einsKonto wird aber in verschiedenen Methoden benötigt. Deshalb
muss sie als Instanzvariable vereinbart werden. Sie ist somit zu Beginn der Klassendefinition zu deklarieren:
public class Kontofuehrung2UI
{
Sparkonto2 einsKunde, zweiKunde;
3.6
// Objektvariablen
Methoden überladen
Methoden haben in Java eine sogenannte Signatur. Sie besteht aus dem Namen der
Methode sowie aus der Anzahl und Reihenfolge der Parameterdatentypen. Diese Angaben kennzeichnen eine Methode. Folglich werden namensgleiche Methoden in einer
Klasse, die eine unterschiedliche Signatur aufweisen, als unterschiedliche Methoden
erkannt.
Beispiel
a)
public double berechne ( int a, double b, int c)
b)
public double berechne (double a, int b, double c)
c)
public void berechne (double a, int b)
Alle drei Methoden tragen den Namen berechne. Es sind unterschiedliche Methoden, da
sie sich hinsichtlich des Rückgabewertes, Anzahl der Parameter wie auch der Datentypen der Parameter unterscheiden.
Bei einem Methodenaufruf der Form
System.out.print (objektvariable.berechne(17.5, 6, 58.44) )
würde die Methode b) aufgerufen, weil da die Parameter in Anzahl und Datentyp übereinstimmen. Das Java-System würde die Methode a) nicht aufrufen, weil dort die Datentypen der Parameter nicht „passen“. Die Methode c) wird in einem Ausgabebefehl
ignoriert, weil sie keinen Rückgabewert aufweist.
Ein weiteres Beispiel: Es sollen die Zinsen eines Guthabens berechnet werden. Dazu
wurde die Klasse Sparkonto3 gebildet. In der Methode
[18]
public double getKontostand (int tage) {
wird ein Zinssatz angewendet, der in einer Instanzvariablen festgelegt wurde. Als aktueller Parameter wird lediglich eine Ganzzahl für die Anzahl der Zinstage erwartet.
In der gleichnamigen Methode
[23]
0804_01.indb 61
public double getKontostand (int tage, double zinssatz) {
27.03.2012 11:20:08
128
Auswahlanweisung
Darstellung der zweiseitigen Auswahl in Form eines Programmablaufplans:
Die zweiseitige Auswahl ist in dem Struktogramms farblich hervorgehoben.
0804_01.indb 128
27.03.2012 11:20:20
Auswahlanweisung
139
}
public static void main (String args[]) {
Kdrabatt1 kr = new Kdrabatt1();
kr.Rabattberechnen();
}
}
Der Programmlauf führt zu folgenden Ergebnissen
Eingabe Kundennummer 4000
Rabattsatz 10
Eingabe Kundennummer 6000
Rabattsatz 0
Eingabe Kundennummer 2000
Rabattsatz 12
Ergebnis falsch! Richtig wäre 0
Ergebnis falsch! richtig wäre 10
Ergebnis richtig! 12
Die Ergebnisse sind mit Ausnahme des letzten falsch. Somit ist das Progamm fehlerhaft, auch wenn es optisch richtig aussieht. Der Grund dafür: das else in (3) wird der
Regel entsprechend auf das unmittelbar voraufgehende if in (2) bezogen.
Um das else in (3) dem if (kdnr <= 5000) in Anweisung (1) zuordnen zu können, muss man
sich eines „Tricks“ bedienen. Man schiebt hinter die Anweisung rabsatz = 12; in Anweisung (4) noch ein else mit einer Leeranweisung ein.
import java.util.Scanner;
public class Kdrabatt2
{
int kdnr, rabsatz = 0;
public Kdrabatt2() {
}
public void Rabattberechnen() {
Scanner sc = new Scanner (System.in);
System.out.print ("Eingabe Kundennummer ");
kdnr = sc.nextInt();
if (kdnr <= 5000)
if (kdnr < 3000)
rabsatz = 12;
else;
// eingeschobene Leeranweisung
else
rabsatz = 10;
System.out.println("Rabattsatz "+ rabsatz);
}
//(1)
//(2)
public static void main (String args[]) {
0804_01.indb 139
27.03.2012 11:20:21
Wiederholungsanweisungen
168
In Java gibt es folgende Wiederholungsanweisungen:
•
while
•
do while
•
for
6.1
Kopfgesteuerte Schleife: while
6.1.1
Funktionsweise
Die while-Schleife sei am Beispiel der Durchschnittsrechnung dargestellt. Dabei werden
die eingegebenen Werte summiert. Nach Abschluss der Eingabe wird die Summe durch
die Anzahl der eingegebenen Werte dividiert.
Der Grob-Algorithmus, dargestellt im Pseudo-Code ist leicht einsehbar:
Algorithmus Durchschnitt
Summe = 0
Eingabe Zahl
Solange Zahl > 0
Summenbildung
Anzahl erhöhen
Eingabe Zahl
Durchschnittsberechnung
Ausgabe Durchschnitt
Ende
In Form eines Struktogramms stellt sich der Algorithmus wie folgt dar.
0804_01.indb 168
27.03.2012 11:20:26
Objektsammlungen
213
[54]
// :::::::::::::main::::::::::::::::::::::::::::
[55]
public static void main(String args[]) {
[56]
Umsatz3 ums3 = new Umsatz3();
[57]
ums3.run();
[58]
}
[59] }
Die Beschriftung für die beiden Dimensionen wurde in den Feld-Konstanten DEPA und
QUARTAL notiert. Sie verfügen damit über die Methode length. Diese Methode liefert
die Anzahl der Elemente eines Objektes. Somit können Sie DEPA.length und QUARTALE.length zur Instanziierung von umsatzTabelle (Zeile 6) wie auch zur Schleifensteuerung
verwenden.
for (int s = 0; s < DEPA.length; s++)
for (int z = 0; z < QUARTALE.length; z++)
Auf diese Weise stellt man sicher, dass die Feld-Grenzen nicht überschritten werden.
7.2
Felder für Objekte
In Feldern können nicht nur einfache Datentypen, sondern auch Objekte angelegt und
verwaltet werden.
Problem
Für ein Hotel ist eine (vereinfachte) Zimmerverwaltung zu erstellen. Es verfügt über fünf
Zimmer. Jedes Zimmer sei gekennzeichnet durch die Eigenschaften Zimmernummer,
Preis und Belegt-Status.
Hotelzimmer
zimmernummer: int
preis: double
belegt: boolean
zimmerEinrichten()
zimmerDrucken()
/**
* Eigenschaften des Hotelzimmers.
*/
public class Hotelzimmer
{
int zimmerNr;
double preis;
boolean belegt = false;
public Hotelzimmer() {
}
0804_01.indb 213
27.03.2012 11:20:33
Objektsammlungen
216
Das Programm läuft in der Weise ab, dass in der main-Methode das Objekt Hotel1 angelegt und dort die Methode run() aufgerufen wird. In der run()-Methode wird die Methode einrichten() gestartet, in der die Hotelzimmer instanziiert und mit Werten versorgt
werden. Anschließend erfolgt der Ausdruck der Zimmerdaten. Die Ausgabe der Überschrift erfolgt in der Methode zimmerListeDrucken(). Die Datenausgabe wird in der Methode zimmerDrucken() im Objekt Hotelzimmer vorgenommen. Die Steuerung der Datenausgabe erfolgt durch die for-Anweisung in der Methode zimmerListeDrucken.
7.3
ArrayList
7.3.1
ArrayList bei vordefiniertem Objekttyp
Ein Feld kann bei solchen Problemstellungen eingesetzt werden, bei denen die Anzahl
der Elemente zu Beginn der Programmnutzung bekannt sind. Das ist im Beispiel der
Hotelzimmer wohl gegeben. Wenn es aber darum geht, die Daten von Objekten zu erfassen, deren Anzahl nicht im Vorhinein bekannt ist, ist das Feld nicht gut geeignet. Hier
ist dann eine Klasse gefragt, die die Daten dynamisch verwalten kann.
Problem
In „unserem“ Hotel werden Veranstaltungen durchgeführt, zu denen man sich vorher
anmelden muss. Die Anmeldungen erfolgen telefonisch. Zu erfassen ist der Name des
Gastes. Der Veranstalter braucht neben der Anzahl der angemeldeten Personen eine
Liste mit der Reihenfolge der Anmeldungen sowie eine alphabetisch sortierte Liste. Da
sich Personen auch wieder abmelden können, muss es die Möglichkeit geben, Namen
aus der Liste zu entfernen.
Diese Programmanforderungen sind mit einem Feld-Objekt nicht zu erfüllen. Hier bietet
sich die Klasse ArrayList an. Sie ist in dem Paket java.util enthalten. Das nachstehende
Programmlisting zeigt am Beispiel der Klasse Gaesteliste, wie die Klasse ArrayList verwendet wird.
0804_01.indb 216
27.03.2012 11:20:34
Vererbung, Polymorphie und Interface
250
8
Vererbung, Polymorphie und Interface
8.1
Konzept
Die Vererbung ist eines der wichtigsten Konzepte einer objektorientierten Programmiersprache. Sie sei am Beispiel einer vereinfachten Lohnabrechnung dargelegt.
Beispiel
Bei der Lohnberechnung muss zwischen Angestellten und Arbeitern unterschieden werden. Die Angestellten erhalten ein feststehendes Monatsgehalt. Bei den Arbeitern bildet
sich der Lohn aus der Multiplikation von Stundenlohn und Anzahl der Arbeitsstunden.
Der Stundenlohn sei hier mit 25,00 Euro vorgegeben. Die Kinderzulage, die der Betrieb
freiwillig zahlt, richtet sich nach der Anzahl der Kinder. Pro Kind beträgt die Zulage
50,00 Euro.
Man könnte nun zwei Klassen bilden:
Angestellter
Arbeiter
Name
Kinderzahl
Monatsgehalt
Name
Kinderzahl
Stundenlohn
berechneKinderzulage
berechneMonatslohn
berechneKinderzulage
berechneMonatslohn
Zwei fast gleiche Datensätze einzurichten und später programmtechnisch zu betreuen
ist aufwändig. Um den Aufwand zu verringern, bildet man eine eigene Klasse, die die
gemeinsamen Elemente aufnimmt. Diese Klasse nennt man Oberklasse bzw. Superklasse. Die übrigen Elemente verbleiben in der bisherigen Klasse, die dann als Unterklasse oder Subklasse bezeichnet wird. In unserem Beispiel könnte sich folgendes
UML-Diagramm ergeben.
Mitarbeiter
-
Name
-
berechneKinderzulage
Angestellter
Arbeiter
Monatsgehalt
Stundenlohn
berechne Monatslohn
berechneMonatslohn
0804_01.indb 250
27.03.2012 11:20:39
Exeptions – Behandlung von Ausnahmen
281
In diesem Zusammenhang sei auf das sogenannte Auto-Boxing hingewiesen. Danach
lässt Java eine Wertzuweisung eines einfachen Datentyps auf ein Objekt der korrespondierenden Wrapper-Klasse zu. Eine umgekehrte Wertzuweisung ist in diesem Fall auch
zulässig.
9.1.4
Ablauflogik der try-catch-Konstruktion
In dem Einführungsbeispiel ist ein Eingabestring in eine double-Zahl umzuwandeln. Das
ist ein kritischer Vorgang. Wurde ein Buchstabe mit eingegeben, tritt ein Laufzeitfehler
auf. In der Folge bricht das Programm ab. Ebenfalls stürzt das Programm ab, wenn bei
einer Dezimalzahl ein Komma anstatt eines Punktes als Dezimaltrennzeichen verwendet
wurde. Wurde das System auf den deutschen Zeichensatz eingestellt, tritt der Fehler im
umgekehrten Fall auf.
Durch try wird die Ausführung der Zuweisung unter Beobachtung gestellt.
[3
[4]
[5]
try {
zahl = Double.parseDouble(ein);
}
Falls bei dieser Operation ein Fehler auftritt, werden die Anweisungen des catch-Blocks
bearbeitet. Anschließend werden die Methoden ausgeführt, die dem catch-Block folgen.
Trat im try-Block kein Fehler auf, wird der catch-Block übersprungen.
Die nachstehende Abbildung zeigt die Ablauflogik der try-catch-Konstruktion.
Die try-catch-Konstruktion ist im Prinzip einfach. Ein großes Problem besteht jedoch
darin, dass Java nicht zu der Programmstelle zurückkehrt, an der der Fehler aufgetreten
ist. Dafür müssen Sie durch eine entsprechende Programmierung selber sorgen. Das sei
0804_01.indb 281
27.03.2012 11:20:44
Benutzeroberflächen
315
Komponenten hinzufügen
NetBeans erzeugt nun die Klasse Rechnen sowie eine Grundmaske für RechnenGUI.
Diese Maske stellt eine Art Container dar, in dem die Komponenten wie Textfelder,
Beschriftungselemente und Schaltflächen angeordnet werden.
Neben dem Container wird ein Palettenfenster eingeblendet, in dem eine Vielzahl von
Fenster-Elementen bereitgehalten wird. Die Elemente sind in mehrere Gruppen eingeteilt, wie zum Beispiel Swing Containers und Swing Controls. Im unteren Bereich ist ein
Properties-Fenster angesiedelt. In der deutschen NetBeans-Version wird es mit Eigenschaften bezeichnet.
Die Grundmaske lässt sich vergrößern und verkleinern. Probieren Sie es ruhig. Fahren
Sie mit dem Cursor über den rechten bzw. unteren Randbereich. Sobald sich der Cursor
in einen Doppelpfeil verwandelt, können Sie die Grundmaske nach rechts bzw. unten
vergrößern.
Die Benutzeroberfläche soll einen Namen haben. Klicken Sie deshalb mit der rechten
Maustaste in die Grundfläche. Damit rufen Sie ein Kontext-Menü auf, in dem Sie auf
den Auswahlpunkt Properties klicken. Es öffnet sich ein Dialogfenster JFrame. Im Register Properties tragen Sie in der title-Zeile Rechner ein und beenden den Dialog mit
einem Klick auf <Close>.
In die Grundmaske werden nun die Komponenten eingebaut. Zuerst wird ein Rahmen
gezogen. Dazu klicken Sie auf die Komponente Panel im Swing-Container und ziehen
den Rahmen auf die Grundmaske in die linke obere Ecke. Der Feldrahmen ist aktiviert.
Vergrößern Sie ihn auf etwa die Hälfte der Grundmaske und klicken im PropertiesFenster in der Border-Zeile auf den <…>-Button. Damit rufen Sie das Jpanel-BorderFenster auf, in dem Sie auf die Zeile Titled Border klicken. Es wird dann ein Textfeld
Title Border eingeblendet, in das Sie den Begriff Rechnen eingeben.
0804_01.indb 315
27.03.2012 11:20:49
Benutzeroberflächen
319
Die obige Abbildung gibt einen Überblick über die Vielzahl von Ereignissen, die programmtechnisch abgefragt werden können.
11.3
Entwicklung einer komplexen Anwendung
11.3.1
Problemstellung
Die Entwicklung eines Java-Programms für eine komplexe Aufgabenstellung erfolgt am
Beispiel des Paketdienstes, das im letzten Kapitel behandelt wurde. Dort wurde die
Erfassung und Speicherung der Daten mit Hilfe zweier Klassen durchgeführt: Klasse
Paket sowie einer Klasse zur Bearbeitung der Daten. Bei Einsatz einer graphischen Bedienoberfläche arbeitet man mit drei Klassen. Eine Klasse befasst sich mit der Bildschirmmaske und ihren Komponenten. Sie reicht die eingegebenen Daten zur Verarbeitung an die Steuerungsklasse. Diese Klasse verarbeitet die Daten. Die dritte Klasse
beschreibt das Datenmodell.
Bezogen auf die Eingabe und Verarbeitung von Daten kann das Zusammenspiel dieser
drei Klassen wie folgt skizziert werden.
Die Bildschirmmaske könnte wie folgt gestaltet werden:
0804_01.indb 319
27.03.2012 11:20:50
Datenbank-Anwendung
342
ter, in das Sie den Namen der Datenbank eintragen. Hier wurde zum Beispiel ueb3db
vermerkt. Nach dem Klick auf <OK> wird die Datenbank angelegt.
12.4
Mit einer Datenbank arbeiten
Der Zugriff auf die Datenbank kann auf zweierlei Wegen erfolgen. Zum einen bietet
NetBeans ein Bediensystem an, mit dem Sie Tabellen anlegen und ändern, Daten eingeben und anzeigen oder auch SQL-Statements ausführen können. Zum anderen ist ein
Zugriff mittels eines Java-Programms möglich.
12.4.1
Direkter Zugriff auf die Datenbank
Um eine Tabelle anzulegen, klicken Sie im Service-Fenster auf den Knoten vor
jdbc:mysql://localhost:3306/ueb3db. Es werden die mit diesem Treiber angelegten Datenbanken angezeigt.
Anschließend klicken Sie auf den Knoten vor ueb3db. Drei Unterverzeichnisse werden
angezeigt. Klicken Sie mit der rechten Maustaste auf Tables. Mit einem Klick auf Create
Table öffnen Sie das Create Table-Fenster. Dort können Sie die Struktur einer Tabelle
eintragen.
Als Tabellenname geben Sie Ort ein. Anschließend betätigen Sie <Add column>. In das
Add Column-Fenster geben Sie als Spaltenname ortNr und als Typ Smallint an, Abschluss mit <OK>.
0804_01.indb 342
27.03.2012 11:20:53
Datenbank-Anwendung
349
}
Ergebnis:
12.5
Windows-Anwendung und Datenbankzugriff
In den voraufgegangenen Klassen wurden die Eingabedaten oftmals unmittelbar in den
Quellcode hineingeschrieben. Das geschah aus Gründen der Vereinfachung. Diese Vorgehensweise entspricht jedoch nicht den Anforderungen der Praxis. Üblich ist die Eingabe der Daten über eine Bildschirmmaske. Im folgenden Beispiel sollen die Daten der
Mitarbeiter mit Hilfe des nachstehenden Bildschirmformulars eingegeben werden.
Nach der Eingabe des Ortskennzeichens sollen die eingegebenen Daten im Kontrollausdruck angezeigt werden. Nach der Betätigung von <OK> werden die Daten in der Datenbank gespeichert. Darüber wird eine Meldung im Kontrollausdruck gemacht.
0804_01.indb 349
27.03.2012 11:20:55
Herunterladen