Java/Online-Bank: Unterschied zwischen den Versionen
K (20 Versionen importiert) |
Markierung: 2017-Quelltext-Bearbeitung |
||
(50 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
{{ | {{Fortsetzung| | ||
vorher=Einstieg in die OOP|vorherlink=Java/Einstieg in die OOP| | |||
weiter=Algorithmik<br>(Logische Operatoren)|weiterlink=Java/Algorithmik| | |||
übersicht=Einstieg in Java<br>(Übersicht)|übersichtlink=Java#Übersicht|}} | |||
}} | |||
== | ==Einfache Theorie der Objektorientierten Programmierung== | ||
[[Datei:BlueJ Logo.gif|BlueJ Logo|right|200px]] Zunächst klären wir am Beispiel Vogel, was eine '''Klasse''' ist: Ähnlich wie in der Biologie gruppiert man in der OOP (Objektorientierten Programmierung) Objekte und fasst sie in Klassen zusammen. Dabei stellt sich die Frage, was einen Vogel auszeichnet: | |||
und | |||
*Ein Vogel kann bestimmte Dinge tun. Er kann etwa singen oder ein Ei legen. Das sind die sogenannten '''Methoden (Operationen)''' des Vogels (<code>singe(...), legeEi(...)</code> ). Methoden teilt man in zwei Gruppen ein: | |||
**'''beobachtende''' oder '''sondierende''' Methoden z.B. <code>gibFarbe()</code> und | |||
**'''verändernde''' oder '''manipulierende''' Methoden wie z.B. <code>setFarbe(“gruen“)</code>. | |||
*Ein Vogel hat auch bestimmte '''Eigenschaften''' ('''Attribute'''). Er hat zum Beispiel eine bestimmte Farbe, ein Geschlecht, eine Flügelspannweite. Die Gesamtheit der Werte dieser Eigenschaften nennt man '''Zustand'''. Hierin unterscheiden sich verschiedene Objekte derselben Klasse. | |||
*Aus der Klasse Vogel lassen sich dann konkrete Objekte bilden z.B. <code>vogel1</code>, <code>vogel2</code>, <code>vogel3</code>. | |||
*Während die '''Klasse''' Vogel etwas '''abstraktes''' ist (eine Art Bauplan für Objekte), ist ein '''Objekt''' '''konkret'''.<br /> | |||
{{ | {{Box|Zusammenfassung| | ||
* ''' | * '''Objekte''' sind in der objektorientierten Programmierung | ||
* | ** '''Daten''' (Eigenschaften oder auch Attribute) und | ||
** die damit verknüpfte '''Programmlogik''' (Methoden oder auch Operationen),<br>die zu Einheiten, nämlich eben den Objekten, zusammengefasst sind. | |||
* Gleichartige Objekte werden zu '''Klassen''' zusammengefasst. | |||
* '''Klassen dienen als Vorlage''' (wie ein Bauplan) zur Herstellung von Objekten. | |||
* Von einer Klasse können beliebig viele Objekte hergestellt werden. | |||
* Die '''Objekte sind einzigartig''', da sie einen unterschiedlichen Namen tragen müssen, obwohl ihr Zustand identisch sein kann. | |||
* Der Zustand (oder auch Status) ist die Gesamtheit der Werte der Eigenschaften.|Hervorhebung}} | |||
==Beispiel: Online-Bank== | |||
===Die Klasse Konto=== | |||
Um ein Konto zu eröffnen, benötigt eine Bank zumindest | |||
*den Namen des Besitzers <code>besitzerName</code> und | |||
*den aktuellen Geldbetrag <code>kontostand</code>. | |||
Beides sind '''Attribute''' (bzw. Eigenschaften) der '''Klasse Konto'''. | |||
{{Definition | *Jedes Attribut verlangt die Angabe eines geeigneten '''Datentyps'''. | ||
*Java kennt u.a. folgende '''Datentypen''': | |||
* | {| class="wikitable" style="text-align:left" | ||
!Typname | |||
!Größe | |||
!Wertebereich | |||
!Beschreibung | |||
|----- | |||
|boolean||1 bit||true / false||Boolescher Wahrheitswert | |||
|- | |||
|int||32 bit||-2.147.483.648 ... 2.147.483.647||Zweierkomplement-Wert | |||
|- | |||
|float||32 bit||+/-1,4E-45 ... +/-3,4E+38||32-bit IEEE 754, einfache Genauigkeit | |||
|- | |||
|double||64 bit||+/-4,9E-324 ... +/-1,7E+308||64-bit IEEE 754, doppelte Genauigkeit | |||
|- | |||
|char||16 bit||0 ... 65.535 (z.B. 'A')||Unicode-Zeichen (UTF-16) | |||
|- | |||
|String|| || ||Zeichenkette (kein einfacher Datentyp,<br>sondern ein Objekt der Klasse String) | |||
|} | |||
====Eingabe des Quelltexts==== | |||
[[Datei:BlueJ Online-Bank 1.png|alternativtext=Online-Bank: Klasse Konto|mini|Online-Bank: Klasse Konto]] | |||
*Mit "Projekt|neu" wird ein neues Projekt angelegt, das wir "Online-Bank" nennen. | |||
*Mit "Neue Klasse" legen wir eine Klasse mit dem Namen "Konto" an. | |||
*Wenn alles richtig geklappt hat, sollte es etwa so aussehen: | |||
Mit einem Doppelklick auf das beige Rechteck kommt zum Editor, in dem man den Quelltext eintippen kann:[[Datei:BlueJ Online-Bank- Neue Instanz konto1-Konto.png|alternativtext=Neue Instanz konto1:Konto|mini|Neue Instanz konto1:Konto]] | |||
<source lang="java"> | |||
public class Konto { | |||
// Instanzvariablen | |||
private String besitzerName; | |||
private double kontostand; | |||
} | |||
</source> | |||
und mit dem Button "Übersetzen" abspeichert und ''"compiliert"''. | |||
*Die '''Definition''' der Klasse beginnt mit dem Schlüsselwort <code>public</code> | |||
*Die '''Zugriffsmodifizierer''' <code>public</code> und <code>private</code> regeln die Zugriffsrechte.<br> Dies ist vergleichbar mit dem Zugriff auf ein technisches Gerät wie z.B. Handy, TV, Auto, Waschmaschine etc.: | |||
**Die Bedienknöpfe sind <code>public</code>, also öffentlich und von jedem bedienbar. | |||
**Das Innenleben des Gerätes ist <code>private</code> und ein Laie sollte hier keinen Zugriff haben. | |||
[[Datei:BlueJ Online-Bank 3.png|alternativtext=Online-Bank: Objektinspektor|mini|500x500px]] | |||
Als erste Faustregel genügt es, sich zu merken, dass | |||
*'''Attribute''' <code>private</code> (Innenleben der Klasse) und | |||
*'''Klassen''' <code>public</code>sind. | |||
Instanzieren Sie nun ein Objekt <code>Konto1</code> der Klasse <code>Konto</code> mit der Methode <code>new Konto()</code> wähle. | |||
====Objektinspektor==== | |||
Ein Rechtsklick auf das rote Rechteck und dann auf Inspizieren öffnet den '''Objektinspektor'''. Dieser gibt einen Überblick über den '''Zustand''' des Objektes: | |||
*Unser Besitzer heißt <code>null</code>,<br> dem Anfangswert für String-Variablen. | |||
*Der Kontostand ist <code>0</code>,<br> dem Anfangswert für numerische Variablen. | |||
{{Box|Zusammenfassung| | |||
*Eine Klasse definiert man im Quelltextes. Der minimale Aufbau ist: | |||
<source lang="java""> | |||
public class Klassenname { | |||
// Instanzvariablen | |||
private Datentyp eigenschaft1; | |||
private Datentyp eigenschaft2; | |||
} | |||
</source> | |||
* Die Zugriffsmodifizierer <code>public</code> und <code>private</code> regeln die Zugriffsrechte. | |||
* Als vorläufige Regel ist die Klasse immer <code>public</code> und die Eigenschaften immer <code>private</code>. | |||
* Aus Klassen lassen sich Objekte erzeugen, die einen eindeutigen Namen tragen müssen. | |||
* Die Objekte haben einen Zustand, den man mit Hilfe des Objektinspektors ansehen kann. | |||
** Anfangszustand von Strings ist das englische Wort <code>null</code> und von Zahlentypen <code>0</code>. | |||
* Ein „Doppelslash“ <code>//</code> am Anfang der Zeile macht aus der Zeile einen Kommentar, den der Computer ignoriert.|Hervorhebung2}} | |||
{{Übung| | |||
# Erweitern Sie die Klasse Konto um die Attribute <code>kreditLimit</code> und <code>telefonNummer</code>.<br> Welche Datentypen würden Sie verwenden? | |||
# Recherchieren Sie, welche weiteren numerischen Datentypen Java bietet? | |||
}} | }} | ||
===Der Konstruktor=== | |||
Der '''Konstruktor''' ist eine spezielle Methode, die bei der Erzeugung von Variablen aufgerufen wird und diese in einen definierten Anfangszustand versetzt. Dieser Vorgang nennt sich auch '''Initialisierung'''. | |||
<source lang="java"> | |||
public class Konto { | |||
// Instanzvariablen | |||
private String besitzerName; | |||
private double kontostand; | |||
// Konstruktor | |||
public Konto (String pBesitzerName){ | |||
besitzerName = pBesitzerName; | |||
kontostand = 1.0; | |||
} | |||
} | |||
</source> | |||
''' | {| class="wikitable" | ||
|- | |||
!Begriff!!Erläuterung | |||
|- | |||
|'''Konstruktor'''||Ein Konstruktor ist eine spezielle Methode und legt die Anfangswerte fest. Er erhält den gleichen Namen wie die Klasse selbst z.B. public Konto. Alle Werte, die nicht im Konstruktor festgelegt werden, bekommen einen „default-Wert“. Bei Zahlentypen ist das 0, bei Strings „null“ | |||
|- | |||
|(Übergabe-) '''Parameter'''||Sind die Werte, die der Methode beim Aufruf übergeben werden. Für jeden Parameter muss ein Datentyp festgelegt werden. Der Name des Parameters kann zur besseren Übersicht mit p beginnen. | |||
|- | |||
|geschweifte Klammern||Sie strukturieren das Programm: Die gesamte Klasse und jede Methoden wie z.B. der Konstruktor stehen in geschweiften Klammern. Das Weglassen von Klammern ist eine typische Fehlerquelle. | |||
|- | |||
|'''amerikanische Notation'''||Verwenden Sie im Quelltext | |||
*bei Zahlendarstellungen stets '''Punkt statt Komma''': 3.141 | |||
*'''keine deutschen Umlaute oder Sonderzeichen'''!! | |||
|- | |||
|Semikolon||Nach (nahezu) jedem Befehl (Anweisung) möchte Java ein Semikolon ; | |||
|} | |||
{{Übung| | {{Übung| | ||
# Erweitern Sie die Instanzvariablen mit dem String <code>strassenName</code>.<br> Im Konstruktor trennen Sie mehrere Übergabeparameter durch Kommata: <code>public Konto (String pBesitzerName, String pStrassenName)</code> | |||
* | # Testen Sie Fehleingaben bei BlueJ: Lassen Sie beim Besitzernamen die Anführungsstriche weg, geben Sie eine Zahl, geben Sie nichts ein … | ||
# Lassen Sie statt des Namens den Kontostand als Parameter übergeben. | |||
# Ergänzen Sie die Eigenschaften <code>vorname</code>, <code>telefonnummer</code>, <code>postleitzahl</code>, <code>geburtsjahr</code>, <code>geschlecht</code> und <code>hausnummer</code>. Begründen Sie dabei, welche Datentypen Sie verwenden.}} | |||
===Methoden === | |||
Die Methode <code>einzahlen(double pBetrag)</code> sorgt dafür, dass zu dem bisherigen Kontostand ein bestimmter Betrag hinzugefügt wird: | |||
<source lang="java"> | |||
public void einzahlen(double pBetrag){ | |||
kontostand += pBetrag; | |||
// oder kontostand = kontostand + pBetrag; | |||
}</source> | |||
====Zuweisen von Werten an Variablen==== | |||
Das "''Gleichheits''"-zeichen wird in Java nicht als Vergleichs-, sondern als '''Zuweisungsoperator''' verwendet: | |||
* Auf der linken Seite des Zuweisungsoperators steht die Variable, die einen neuen Wert bekommen soll, | |||
* auf der rechten Seite eine Rechnung, die den neuen Wert ergibt.<br> Die Variable links darf dabei als (alter) Variablenwert in der Rechnung rechts vorkommen: | |||
** <code>x = y + 7</code> bedeutet, dass x den Wert der Rechnung y + 7 bekommt. | |||
** <code>x = x + 7</code> bedeutet, dass x um 7 erhöht wird | |||
** <code>x += 7</code> Kurzschreibweise: x wird um 7 erhöht (analog <code>-=</code>). | |||
** <code>x *= 7</code> Kurzschreibweise: x wird mit 7 multipliziert (analog <code>/=</code>). | |||
** <code>x++</code> x wird um 1 erhöht | |||
** <code>x--</code> x wird um 1 erniedrigt | |||
{{Übung|# Bauen Sie die Methode <code>einzahlen</code> in Ihre Kontoklasse ein. | |||
# Testen Sie das Einzahlen von negativen Beträgen, großen Beträgen, 0, Wörtern, Rechnungen... | |||
# Entwerfen Sie auf Grundlage von <code>einzahlen</code> die Methode <code>auszahlen()</code>. | |||
# Schreiben Sie die Methode <code>bucheZinsen (double pzinssatz)</code>,<br>die auf den vorliegenden Kontostand <code>zinssatz</code> Prozent Zinsen addiert. | |||
# Entwerfen Sie <code>raubeAus()</code>, die den Kontostand auf 0 setzt. | |||
}} | }} | ||
== | ====Die set-Methoden als Beispiel für verändernde Methode ohne Rückgabewert==== | ||
Diese einfache Methode verändert den Namen des Kontobesitzers: | |||
<source lang="java"> | |||
public void setBesitzerName(String pNeuerName){ | |||
besitzerName = pNeuerName; | |||
}</source> | |||
{{Merke|Wann schreibt man void? | |||
* <code>void</code> kommt bei einer Methodendeklaration immer dann vor, wenn es keine Rückgabe (void: nichts) gibt. | |||
* <code>return</code> Gibt es eine Rückgabe (return variable), so muss der Datentyp des Rückgabewertes eingetragen werden.}} | |||
====Die get-Methoden als Beispiel für sondierende Methoden==== | |||
Eine ebenso einfache Methode liest den Namen des Kontobesitzers wieder aus: | |||
<source lang="java"> | |||
public String getBesitzerName(){ | |||
return besitzerName; | |||
}</source> | |||
{{Übung|Schreiben Sie get-Methoden, die die den Kontostand und den Zinssatz ausgeben.}} | |||
==Interaktion zwischen Objekten== | |||
Zu einer Bank gehören mehrere Konten und neben Ein- und Auszahlungen auch Überweisungen bzw. '''Interaktionen''': | |||
<source lang="java"> | |||
public void ueberweise(double pBetrag, Konto pZielkonto){ | |||
auszahlen(pBetrag); | |||
pZielkonto.einzahlen(pBetrag); | |||
}</source> | |||
* Es gibt diesmal '''zwei Übergabeparameter''', die wir, wie schon beim Konstruktor, mit Komma trennen. Die Besonderheit ist, dass der Datentyp von Zielkonto wieder ein Konto ist. | |||
* Man darf sogar in Methoden den Datentypen der Klasse verwenden, zu dem die Methode gehört. Das ist sinnvoll, denn üblicherweise möchte man von einem Konto auf ein anderes Konto überweisen. | |||
* Eigenschaften, die private sind, sind nur für Objekte der gleichen Klasse sichtbar. Theoretisch könnten wir von dem einen Konto auf die Eigenschaften des anderen Kontos direkt zugreifen. Damit es nicht zu Verwechslungen bzw. sogenannten Seiteneffekten kommt, sollten Sie das unbedingt vermeiden!! | |||
{{Box|Konvention| | |||
* Auf die Daten von '''fremden''' Objekten oder Klassen greifen wir | |||
**'''immer über Methoden''' und | |||
**'''nie über deren Eigenschaften''' zu. | |||
* Dies gewährleistet, dass nichts Ungewolltes verändert wird!. Deshalb sind sie ja ''private''! | |||
* '''Nur innerhalb des Objektes selbst''' verändert man die eigenen Eigenschaften direkt.|Hervorhebung}} | |||
{{Übung|# Schreiben Sie die Methode <code>holeEinzug (double pBetrag, Konto pZielkonto)</code>,<br> bei dem das Geld von einem fremden Konto überwiesen wird. | |||
# Schreiben Sie die Methode <code>vererben (Konto erbe)</code>,<br> bei dem das gesamte Geld eines Kontos auf ein anderes verbucht wird. | |||
# Schreiben Sie die Methode <code>binIchReich(Konto vergleichskonto)</code>,<br> das die Differenz aus dem eigenen Kontostand mit einem anderen Konto vergleicht. | |||
# Schreiben Sie die Methode <code>stifteVerwirrung(Konto konto1, Konto konto2)</code>,<br> bei der ein unbeteiligtes Konto dafür sorgt, dass das gesamte Geld von <code>konto1</code> auf </code>konto2</code> überwiesen wird. | |||
# Schreiben Sie die Methode <code>stifteNochMehrVerwirrung(Konto konto1, Konto konto2)</code>,<br> bei der ein unbeteiligtes Konto dafür sorgt, dass das gesamte Geld von <code>konto1</code> halbiert, das von <code>konto2</code> aber verdoppelt wird. | |||
# Lassen Sie von einem Konto den Namen des Besitzers eines anderen Kontos ändern. Welche Probleme ergeben sich, wenn Sie die Methode <code>setBesitzerName</code> weglassen? | |||
}} | |||
{{Fortsetzung| | |||
vorher=Einstieg in die OOP|vorherlink=Java/Einstieg in die OOP| | |||
weiter=Algorithmik<br>(Logische Operatoren)|weiterlink=Java/Algorithmik| | |||
übersicht=Einstieg in Java<br>(Übersicht)|übersichtlink=Java#Übersicht|}} | |||
==Weitere Beispiele== | |||
===Der Zähler=== | |||
* Der Zähler ist eine einfache Klasse, bei dem Sie bei Aufruf der Methode <code>erhoeheZaehlerstand()</code> den Zähler um 1 erhöhen. | |||
* Anwendungen: Verkehrszählungen, Heizungsverbrauchzähler, Bildzähler bei einer Kamera, Rundenzähler bei der Carrera-Bahn... | |||
* Bei den realen Anwendungen kommt der Impuls von einem Sensor bzw. einen Druckknopf. Bei der Simulation müssen Sie statt dessen eine Methode ausführen. | |||
<source lang="java"> | |||
public class Zaehler{ | |||
// Instanzvariablen der Eigenschaften | |||
int zaehlerstand; | |||
// Konstruktor | |||
public Zaehler(){ | |||
// Der Anfangszählerstand soll immer 0 sein. | |||
zaehlerstand=0; | |||
} | |||
// Methoden | |||
public void erhoeheZaehlerstand(){ | |||
zaehlerstand += 1; | |||
// oder zaehlerstand++; | |||
// oder zaehlerstand=zaehlerstand+1; | |||
} | |||
}</source> | |||
===Das Telefonbuch=== | |||
[[Datei:Klassendiagramm-Telefonbuch.png|300px|right]] | |||
* Die Telefonnummer wird, obwohl sie laut Name eine Nummer ist, als String eingelesen, um Eingaben wie „/“ zwischen Vorwahl und Nummer zuzulassen. | |||
* Die Besonderheit an dieser Klasse ist, dass <code>name</code> nur durch den Konstruktor verändert werden kann. D.h. ich kann zwar mit <code>setTelefonnummer</code> nachträglich Telefonnummern ändern, aber der Name bleibt erhalten. | |||
* Allenfalls durch das Löschen des Objektes kann ich Personen aus dem Telefonbuch entfernen. | |||
<source lang="java">public class Telefonbuch { | |||
// Eigenschaften | |||
// Anfang Variablen | |||
public String name; | |||
public String telefonnummer; | |||
// Ende Variablen | |||
// Konstruktor | |||
public Telefonbuch(String name, String telefonnummer) { | |||
// ... Hier fehlen 2 Zeilen. Bitte nachtragen! (vgl. Übung) | |||
} | |||
// Anfang Ereignisprozeduren | |||
// Methoden | |||
public String getTelefonnummer() { | |||
return telefonnummer; | |||
} | |||
public void setTelefonnummer(String pTelefonnummer) { | |||
telefonnummer = pTelefonnummer; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
// Ende Ereignisprozeduren | |||
}}</source> | |||
===Das Auto=== | |||
[[Datei:Klassendiagramm-Auto.png|right|300px]] | |||
Die Klasse simuliert ein Auto, erfasst aber nur Daten um den Tank und den Verbrauch. | |||
* Die manipulierenden Methoden <code>tanke(..)</code> und <code>fahre(...)</code> beeinflussen den aktuellen Füllstand. | |||
* Die sondierende Methode <code>getAktuelleMaximaleReichweite</code> gibt die Reichweite in km zurück, der beim aktuellen Füllstand noch gefahren werden kann. | |||
* Die Probleme der Klasse liegen noch darin, dass man (über das Tankvolumen hinaus) soviel tanken kann wie man will und dass der Tankinhalt auch in den negativen Bereich fahren kann (Dispokredit bei der Tankstelle). Das können wir erst lösen, wenn wir die bedingte Ausführung kennen gelernt haben. | |||
<source lang="java">public class Auto { | |||
private double volumenTank; | |||
private double verbrauchAuf100km; | |||
private double aktuellerFuellstand; | |||
{{Übung| | // Konstruktor | ||
public Auto(double pVolumenTank, double pVerbrauchAuf100km) { | |||
volumenTank = pVolumenTank; | |||
}} | verbrauchAuf100km = pVerbrauchAuf100km; | ||
aktuellerFuellstand = 0; // Bei Auslieferung ist der Tank leer | |||
} | |||
// Methoden | |||
public void setAktuellerFuellstand(double pAktuellerFuellstand) { | |||
aktuellerFuellstand = pAktuellerFuellstand; | |||
} | |||
public double getAktuellerFuellstand() { | |||
return aktuellerFuellstand; | |||
} | |||
public double getVerbrauchAuf100km() { | |||
return verbrauchAuf100km; | |||
} | |||
public double getVolumenTank() { | |||
return volumenTank; | |||
} | |||
public void tanke(double menge) { | |||
this.aktuellerFuellstand+=menge; // füge Menge hinzu | |||
} | |||
public void fahre(double pKilometerZahl) { | |||
// Die Formel sagt folgendes aus: | |||
// vom aktuellen Füllstand wird abgezogen: der Verbruch bei der Kilometerzahl | |||
aktuellerFuellstand -= pKilometerZahl / 100 * verbrauchAuf100km; | |||
} | |||
}</source> | |||
{{Übung|# Analysieren und testen Sie alle 3 Programme. Warum bekommt nicht jede Eigenschaft eine get- und eine set-Methode? | |||
# Zu Zähler: | |||
## Ergänzen Sie die Methode: <code>getZaehlerstand()</code> | |||
## Ergänzen Sie die Methode: <code>aufNullSetzen()</code> und <code>erhöheUm(double pZahl)</code> | |||
# Zu Telefonbuch: Ergänzen Sie die fehlenden Zeilen zum Konstruktor. | |||
## Ergänzen Sie die Eigenschaften <code>geburtsdatum</code> (ggf. noch <code>schuhgrösse</code>). | |||
## Welchen Datentypen verwenden Sie? | |||
## Benötigt die Eigenschaft eine set-Methode? | |||
# Zum Auto: Ergänzen Sie die Methode: <code>getMaximaleReichweiteBeiVollemTank()</code> | |||
# Entwickeln Sie die Klasse Handy, die die Eigenschaften <code>telefonnummer</code>, <code>guthaben</code> und <code>gespraechskostenProMinute</code>. Entwickeln Sie geeignete Methoden. | |||
# Übung für Fortgeschrittene: Realisieren Sie die Klasse Bruch mit den Eigenschaften <code>zaehler</code> und <code>nenner</code> und realisieren Sie die Methoden <code>addierenEinerGanzenZahl</code>, <code>kuerzen</code> und <code>erweitern</code>. Wenn Sie schon Vorwissen haben, können Sie hier für eine erweiterte Variante schauen: [https://drdanielappel.de/informatik/mein-kleines-java-tutorium/2-einstieg-in-die-objektorietierte-programmierung/2-04-anwendungsbeispiel-bruchrechnung/ Anwendungsbeispiel Bruchrechnung] (drdanielappel.de)}} | |||
{{Fortsetzung| | |||
vorher=Einstieg in die OOP|vorherlink=Java/Einstieg in die OOP| | |||
weiter=Algorithmik<br>(Logische Operatoren)|weiterlink=Java/Algorithmik| | |||
übersicht=Einstieg in Java<br>(Übersicht)|übersichtlink=Java#Übersicht|}} | |||
== Weblinks == | ==Weblinks== | ||
*vgl. {{wpde|Objektorientierte Programmierung#Klassen|Klassen}} | |||
* | *vgl. {{wpde|Attribut (UML2)|Attribut (UML2)}} | ||
* | *http://www.informatik.ursulaschule.de/index.php?cid=368 | ||
[[Kategorie:Java]] | [[Kategorie:Java]] | ||
[[Kategorie:Informatik]] | [[Kategorie:Informatik]] | ||
[[Kategorie: | [[Kategorie:Unterrichtsidee]] |
Aktuelle Version vom 27. November 2019, 18:48 Uhr
Einfache Theorie der Objektorientierten Programmierung
Zunächst klären wir am Beispiel Vogel, was eine Klasse ist: Ähnlich wie in der Biologie gruppiert man in der OOP (Objektorientierten Programmierung) Objekte und fasst sie in Klassen zusammen. Dabei stellt sich die Frage, was einen Vogel auszeichnet:
- Ein Vogel kann bestimmte Dinge tun. Er kann etwa singen oder ein Ei legen. Das sind die sogenannten Methoden (Operationen) des Vogels (
singe(...), legeEi(...)
). Methoden teilt man in zwei Gruppen ein:- beobachtende oder sondierende Methoden z.B.
gibFarbe()
und - verändernde oder manipulierende Methoden wie z.B.
setFarbe(“gruen“)
.
- beobachtende oder sondierende Methoden z.B.
- Ein Vogel hat auch bestimmte Eigenschaften (Attribute). Er hat zum Beispiel eine bestimmte Farbe, ein Geschlecht, eine Flügelspannweite. Die Gesamtheit der Werte dieser Eigenschaften nennt man Zustand. Hierin unterscheiden sich verschiedene Objekte derselben Klasse.
- Aus der Klasse Vogel lassen sich dann konkrete Objekte bilden z.B.
vogel1
,vogel2
,vogel3
. - Während die Klasse Vogel etwas abstraktes ist (eine Art Bauplan für Objekte), ist ein Objekt konkret.
- Objekte sind in der objektorientierten Programmierung
- Daten (Eigenschaften oder auch Attribute) und
- die damit verknüpfte Programmlogik (Methoden oder auch Operationen),
die zu Einheiten, nämlich eben den Objekten, zusammengefasst sind.
- Gleichartige Objekte werden zu Klassen zusammengefasst.
- Klassen dienen als Vorlage (wie ein Bauplan) zur Herstellung von Objekten.
- Von einer Klasse können beliebig viele Objekte hergestellt werden.
- Die Objekte sind einzigartig, da sie einen unterschiedlichen Namen tragen müssen, obwohl ihr Zustand identisch sein kann.
- Der Zustand (oder auch Status) ist die Gesamtheit der Werte der Eigenschaften.
Beispiel: Online-Bank
Die Klasse Konto
Um ein Konto zu eröffnen, benötigt eine Bank zumindest
- den Namen des Besitzers
besitzerName
und - den aktuellen Geldbetrag
kontostand
.
Beides sind Attribute (bzw. Eigenschaften) der Klasse Konto.
- Jedes Attribut verlangt die Angabe eines geeigneten Datentyps.
- Java kennt u.a. folgende Datentypen:
Typname | Größe | Wertebereich | Beschreibung |
---|---|---|---|
boolean | 1 bit | true / false | Boolescher Wahrheitswert |
int | 32 bit | -2.147.483.648 ... 2.147.483.647 | Zweierkomplement-Wert |
float | 32 bit | +/-1,4E-45 ... +/-3,4E+38 | 32-bit IEEE 754, einfache Genauigkeit |
double | 64 bit | +/-4,9E-324 ... +/-1,7E+308 | 64-bit IEEE 754, doppelte Genauigkeit |
char | 16 bit | 0 ... 65.535 (z.B. 'A') | Unicode-Zeichen (UTF-16) |
String | Zeichenkette (kein einfacher Datentyp, sondern ein Objekt der Klasse String) |
Eingabe des Quelltexts
- Mit "Projekt|neu" wird ein neues Projekt angelegt, das wir "Online-Bank" nennen.
- Mit "Neue Klasse" legen wir eine Klasse mit dem Namen "Konto" an.
- Wenn alles richtig geklappt hat, sollte es etwa so aussehen:
Mit einem Doppelklick auf das beige Rechteck kommt zum Editor, in dem man den Quelltext eintippen kann:
public class Konto {
// Instanzvariablen
private String besitzerName;
private double kontostand;
}
und mit dem Button "Übersetzen" abspeichert und "compiliert".
- Die Definition der Klasse beginnt mit dem Schlüsselwort
public
- Die Zugriffsmodifizierer
public
undprivate
regeln die Zugriffsrechte.
Dies ist vergleichbar mit dem Zugriff auf ein technisches Gerät wie z.B. Handy, TV, Auto, Waschmaschine etc.:- Die Bedienknöpfe sind
public
, also öffentlich und von jedem bedienbar. - Das Innenleben des Gerätes ist
private
und ein Laie sollte hier keinen Zugriff haben.
- Die Bedienknöpfe sind
Als erste Faustregel genügt es, sich zu merken, dass
- Attribute
private
(Innenleben der Klasse) und - Klassen
public
sind.
Instanzieren Sie nun ein Objekt Konto1
der Klasse Konto
mit der Methode new Konto()
wähle.
Objektinspektor
Ein Rechtsklick auf das rote Rechteck und dann auf Inspizieren öffnet den Objektinspektor. Dieser gibt einen Überblick über den Zustand des Objektes:
- Unser Besitzer heißt
null
,
dem Anfangswert für String-Variablen. - Der Kontostand ist
0
,
dem Anfangswert für numerische Variablen.
- Eine Klasse definiert man im Quelltextes. Der minimale Aufbau ist:
public class Klassenname {
// Instanzvariablen
private Datentyp eigenschaft1;
private Datentyp eigenschaft2;
}
- Die Zugriffsmodifizierer
public
undprivate
regeln die Zugriffsrechte. - Als vorläufige Regel ist die Klasse immer
public
und die Eigenschaften immerprivate
. - Aus Klassen lassen sich Objekte erzeugen, die einen eindeutigen Namen tragen müssen.
- Die Objekte haben einen Zustand, den man mit Hilfe des Objektinspektors ansehen kann.
- Anfangszustand von Strings ist das englische Wort
null
und von Zahlentypen0
.
- Anfangszustand von Strings ist das englische Wort
- Ein „Doppelslash“
//
am Anfang der Zeile macht aus der Zeile einen Kommentar, den der Computer ignoriert.
- Erweitern Sie die Klasse Konto um die Attribute
kreditLimit
undtelefonNummer
.
Welche Datentypen würden Sie verwenden? - Recherchieren Sie, welche weiteren numerischen Datentypen Java bietet?
Der Konstruktor
Der Konstruktor ist eine spezielle Methode, die bei der Erzeugung von Variablen aufgerufen wird und diese in einen definierten Anfangszustand versetzt. Dieser Vorgang nennt sich auch Initialisierung.
public class Konto {
// Instanzvariablen
private String besitzerName;
private double kontostand;
// Konstruktor
public Konto (String pBesitzerName){
besitzerName = pBesitzerName;
kontostand = 1.0;
}
}
Begriff | Erläuterung |
---|---|
Konstruktor | Ein Konstruktor ist eine spezielle Methode und legt die Anfangswerte fest. Er erhält den gleichen Namen wie die Klasse selbst z.B. public Konto. Alle Werte, die nicht im Konstruktor festgelegt werden, bekommen einen „default-Wert“. Bei Zahlentypen ist das 0, bei Strings „null“ |
(Übergabe-) Parameter | Sind die Werte, die der Methode beim Aufruf übergeben werden. Für jeden Parameter muss ein Datentyp festgelegt werden. Der Name des Parameters kann zur besseren Übersicht mit p beginnen. |
geschweifte Klammern | Sie strukturieren das Programm: Die gesamte Klasse und jede Methoden wie z.B. der Konstruktor stehen in geschweiften Klammern. Das Weglassen von Klammern ist eine typische Fehlerquelle. |
amerikanische Notation | Verwenden Sie im Quelltext
|
Semikolon | Nach (nahezu) jedem Befehl (Anweisung) möchte Java ein Semikolon ; |
- Erweitern Sie die Instanzvariablen mit dem String
strassenName
.
Im Konstruktor trennen Sie mehrere Übergabeparameter durch Kommata:public Konto (String pBesitzerName, String pStrassenName)
- Testen Sie Fehleingaben bei BlueJ: Lassen Sie beim Besitzernamen die Anführungsstriche weg, geben Sie eine Zahl, geben Sie nichts ein …
- Lassen Sie statt des Namens den Kontostand als Parameter übergeben.
- Ergänzen Sie die Eigenschaften
vorname
,telefonnummer
,postleitzahl
,geburtsjahr
,geschlecht
undhausnummer
. Begründen Sie dabei, welche Datentypen Sie verwenden.
Methoden
Die Methode einzahlen(double pBetrag)
sorgt dafür, dass zu dem bisherigen Kontostand ein bestimmter Betrag hinzugefügt wird:
public void einzahlen(double pBetrag){
kontostand += pBetrag;
// oder kontostand = kontostand + pBetrag;
}
Zuweisen von Werten an Variablen
Das "Gleichheits"-zeichen wird in Java nicht als Vergleichs-, sondern als Zuweisungsoperator verwendet:
- Auf der linken Seite des Zuweisungsoperators steht die Variable, die einen neuen Wert bekommen soll,
- auf der rechten Seite eine Rechnung, die den neuen Wert ergibt.
Die Variable links darf dabei als (alter) Variablenwert in der Rechnung rechts vorkommen:x = y + 7
bedeutet, dass x den Wert der Rechnung y + 7 bekommt.x = x + 7
bedeutet, dass x um 7 erhöht wirdx += 7
Kurzschreibweise: x wird um 7 erhöht (analog-=
).x *= 7
Kurzschreibweise: x wird mit 7 multipliziert (analog/=
).x++
x wird um 1 erhöhtx--
x wird um 1 erniedrigt
- Bauen Sie die Methode
einzahlen
in Ihre Kontoklasse ein. - Testen Sie das Einzahlen von negativen Beträgen, großen Beträgen, 0, Wörtern, Rechnungen...
- Entwerfen Sie auf Grundlage von
einzahlen
die Methodeauszahlen()
. - Schreiben Sie die Methode
bucheZinsen (double pzinssatz)
,
die auf den vorliegenden Kontostandzinssatz
Prozent Zinsen addiert. - Entwerfen Sie
raubeAus()
, die den Kontostand auf 0 setzt.
Die set-Methoden als Beispiel für verändernde Methode ohne Rückgabewert
Diese einfache Methode verändert den Namen des Kontobesitzers:
public void setBesitzerName(String pNeuerName){
besitzerName = pNeuerName;
}
Wann schreibt man void?
void
kommt bei einer Methodendeklaration immer dann vor, wenn es keine Rückgabe (void: nichts) gibt.return
Gibt es eine Rückgabe (return variable), so muss der Datentyp des Rückgabewertes eingetragen werden.
Die get-Methoden als Beispiel für sondierende Methoden
Eine ebenso einfache Methode liest den Namen des Kontobesitzers wieder aus:
public String getBesitzerName(){
return besitzerName;
}
Interaktion zwischen Objekten
Zu einer Bank gehören mehrere Konten und neben Ein- und Auszahlungen auch Überweisungen bzw. Interaktionen:
public void ueberweise(double pBetrag, Konto pZielkonto){
auszahlen(pBetrag);
pZielkonto.einzahlen(pBetrag);
}
- Es gibt diesmal zwei Übergabeparameter, die wir, wie schon beim Konstruktor, mit Komma trennen. Die Besonderheit ist, dass der Datentyp von Zielkonto wieder ein Konto ist.
- Man darf sogar in Methoden den Datentypen der Klasse verwenden, zu dem die Methode gehört. Das ist sinnvoll, denn üblicherweise möchte man von einem Konto auf ein anderes Konto überweisen.
- Eigenschaften, die private sind, sind nur für Objekte der gleichen Klasse sichtbar. Theoretisch könnten wir von dem einen Konto auf die Eigenschaften des anderen Kontos direkt zugreifen. Damit es nicht zu Verwechslungen bzw. sogenannten Seiteneffekten kommt, sollten Sie das unbedingt vermeiden!!
- Auf die Daten von fremden Objekten oder Klassen greifen wir
- immer über Methoden und
- nie über deren Eigenschaften zu.
- Dies gewährleistet, dass nichts Ungewolltes verändert wird!. Deshalb sind sie ja private!
- Nur innerhalb des Objektes selbst verändert man die eigenen Eigenschaften direkt.
- Schreiben Sie die Methode
holeEinzug (double pBetrag, Konto pZielkonto)
,
bei dem das Geld von einem fremden Konto überwiesen wird. - Schreiben Sie die Methode
vererben (Konto erbe)
,
bei dem das gesamte Geld eines Kontos auf ein anderes verbucht wird. - Schreiben Sie die Methode
binIchReich(Konto vergleichskonto)
,
das die Differenz aus dem eigenen Kontostand mit einem anderen Konto vergleicht. - Schreiben Sie die Methode
stifteVerwirrung(Konto konto1, Konto konto2)
,
bei der ein unbeteiligtes Konto dafür sorgt, dass das gesamte Geld vonkonto1
auf konto2 überwiesen wird. - Schreiben Sie die Methode
stifteNochMehrVerwirrung(Konto konto1, Konto konto2)
,
bei der ein unbeteiligtes Konto dafür sorgt, dass das gesamte Geld vonkonto1
halbiert, das vonkonto2
aber verdoppelt wird. - Lassen Sie von einem Konto den Namen des Besitzers eines anderen Kontos ändern. Welche Probleme ergeben sich, wenn Sie die Methode
setBesitzerName
weglassen?
Weitere Beispiele
Der Zähler
- Der Zähler ist eine einfache Klasse, bei dem Sie bei Aufruf der Methode
erhoeheZaehlerstand()
den Zähler um 1 erhöhen. - Anwendungen: Verkehrszählungen, Heizungsverbrauchzähler, Bildzähler bei einer Kamera, Rundenzähler bei der Carrera-Bahn...
- Bei den realen Anwendungen kommt der Impuls von einem Sensor bzw. einen Druckknopf. Bei der Simulation müssen Sie statt dessen eine Methode ausführen.
public class Zaehler{
// Instanzvariablen der Eigenschaften
int zaehlerstand;
// Konstruktor
public Zaehler(){
// Der Anfangszählerstand soll immer 0 sein.
zaehlerstand=0;
}
// Methoden
public void erhoeheZaehlerstand(){
zaehlerstand += 1;
// oder zaehlerstand++;
// oder zaehlerstand=zaehlerstand+1;
}
}
Das Telefonbuch
- Die Telefonnummer wird, obwohl sie laut Name eine Nummer ist, als String eingelesen, um Eingaben wie „/“ zwischen Vorwahl und Nummer zuzulassen.
- Die Besonderheit an dieser Klasse ist, dass
name
nur durch den Konstruktor verändert werden kann. D.h. ich kann zwar mitsetTelefonnummer
nachträglich Telefonnummern ändern, aber der Name bleibt erhalten. - Allenfalls durch das Löschen des Objektes kann ich Personen aus dem Telefonbuch entfernen.
public class Telefonbuch {
// Eigenschaften
// Anfang Variablen
public String name;
public String telefonnummer;
// Ende Variablen
// Konstruktor
public Telefonbuch(String name, String telefonnummer) {
// ... Hier fehlen 2 Zeilen. Bitte nachtragen! (vgl. Übung)
}
// Anfang Ereignisprozeduren
// Methoden
public String getTelefonnummer() {
return telefonnummer;
}
public void setTelefonnummer(String pTelefonnummer) {
telefonnummer = pTelefonnummer;
}
public String getName() {
return name;
}
// Ende Ereignisprozeduren
}}
Das Auto
Die Klasse simuliert ein Auto, erfasst aber nur Daten um den Tank und den Verbrauch.
- Die manipulierenden Methoden
tanke(..)
undfahre(...)
beeinflussen den aktuellen Füllstand. - Die sondierende Methode
getAktuelleMaximaleReichweite
gibt die Reichweite in km zurück, der beim aktuellen Füllstand noch gefahren werden kann. - Die Probleme der Klasse liegen noch darin, dass man (über das Tankvolumen hinaus) soviel tanken kann wie man will und dass der Tankinhalt auch in den negativen Bereich fahren kann (Dispokredit bei der Tankstelle). Das können wir erst lösen, wenn wir die bedingte Ausführung kennen gelernt haben.
public class Auto {
private double volumenTank;
private double verbrauchAuf100km;
private double aktuellerFuellstand;
// Konstruktor
public Auto(double pVolumenTank, double pVerbrauchAuf100km) {
volumenTank = pVolumenTank;
verbrauchAuf100km = pVerbrauchAuf100km;
aktuellerFuellstand = 0; // Bei Auslieferung ist der Tank leer
}
// Methoden
public void setAktuellerFuellstand(double pAktuellerFuellstand) {
aktuellerFuellstand = pAktuellerFuellstand;
}
public double getAktuellerFuellstand() {
return aktuellerFuellstand;
}
public double getVerbrauchAuf100km() {
return verbrauchAuf100km;
}
public double getVolumenTank() {
return volumenTank;
}
public void tanke(double menge) {
this.aktuellerFuellstand+=menge; // füge Menge hinzu
}
public void fahre(double pKilometerZahl) {
// Die Formel sagt folgendes aus:
// vom aktuellen Füllstand wird abgezogen: der Verbruch bei der Kilometerzahl
aktuellerFuellstand -= pKilometerZahl / 100 * verbrauchAuf100km;
}
}
- Analysieren und testen Sie alle 3 Programme. Warum bekommt nicht jede Eigenschaft eine get- und eine set-Methode?
- Zu Zähler:
- Ergänzen Sie die Methode:
getZaehlerstand()
- Ergänzen Sie die Methode:
aufNullSetzen()
underhöheUm(double pZahl)
- Ergänzen Sie die Methode:
- Zu Telefonbuch: Ergänzen Sie die fehlenden Zeilen zum Konstruktor.
- Ergänzen Sie die Eigenschaften
geburtsdatum
(ggf. nochschuhgrösse
). - Welchen Datentypen verwenden Sie?
- Benötigt die Eigenschaft eine set-Methode?
- Ergänzen Sie die Eigenschaften
- Zum Auto: Ergänzen Sie die Methode:
getMaximaleReichweiteBeiVollemTank()
- Entwickeln Sie die Klasse Handy, die die Eigenschaften
telefonnummer
,guthaben
undgespraechskostenProMinute
. Entwickeln Sie geeignete Methoden. - Übung für Fortgeschrittene: Realisieren Sie die Klasse Bruch mit den Eigenschaften
zaehler
undnenner
und realisieren Sie die MethodenaddierenEinerGanzenZahl
,kuerzen
underweitern
. Wenn Sie schon Vorwissen haben, können Sie hier für eine erweiterte Variante schauen: Anwendungsbeispiel Bruchrechnung (drdanielappel.de)