Ziele und Überblick
Die folgende Lerneinheit wiederholt und vertieft den Entwurf von Klassen und deren Implementation.
Konten und Kredite werden in deiner Zukunft vermutlich eine wichtige Rolle spielen: Eventuell bekommst du schon dein Taschengeld auf ein Konto eingezahlt oder verfügst über ein Sparkonto mit Geld für deine Ausbildung. Oder du möchtest mal ein Haus bauen bzw. kaufen und brauchst einen Kredit.
Konten
Die Klasse Konto
In diesem Abschnitt vertiefst du die objektorientierte Modellierung und Programmierung durch Erstellung eins Kontos und einer ersten Version der Klasse Bank.
Auftragseingang der Erkabank
Sehr geehrte Damen und Herren,
mit Freude haben wir die letzten Produkte Ihrer aufstrebenden Softwarefirma betrachtet und sind nun davon überzeugt, dass Sie unsere neue Banking-Software entwickeln können.
Die Anforderungen an den ersten Teil der Software beschränkt sich auf die Kontoverwaltung und werden im Folgenden beschrieben. Ist Ihre Arbeit in diesem Bereich zufriedenstellend, so sind Folgeaufträge wahrscheinlich.
- Jedes Konto hat eine eindeutige IBAN und einen Kontoinhaber. Zur Vereinfachung ist eine IBAN nach folgendem Muster aufgebaut DE0134, also etwas kürzer als in Realität. Vom Kontoinhaber wird der Name gespeichert.
- Auf einem Konto kann man Geld einzahlen.
- Von einem Konto kann man Geld abheben.
- Zudem hat jedes Konto einen Zinssatz für Kapital und einen Dispozinssatz, welche vom Vertrag abhängen. Am Jahresende bekommen alle Konten mit Geld auf dem Konto ihr Geld verzinst. Hat man Schulden auf dem Konto, so können wir unseren höheren Dispozinssatz anwenden. *Teuflisches Lachen*.
- Ein Standardkonto hat zu Beginn einen Zinssatz von 0.4% und einen Dispozinssatz von 6.5%. Allerdings sollen diese Zinssätze jederzeit änderbar sein.
- Die Daten eines Kontos sollen zusammenfassend als Text dargestellt werden können. Überschreiben Sie dazu die toString Methode der Klasse Konto.
Beispiel:
IBAN: DE2165, Kontoinhaber: Testbenutzer9, kapital: 7.973.133,00 €
- Es soll eine Methode geben, welche den aktuellen Zins berechnet. Dieser kann anhand der folgendermaßen berechnet werden \( zins = kapital \cdot \frac{zinssatz}{100.0} \)
- Ferner soll es eine Methode geben, welche das Kapital tatsächlich verzinst.
Mit freundlichen Grüßen
Erkabank
Implementationsdiagramm erstellen
- Erstelle anhand des Auftrags ein Klassendiagramm für die Klasse Konto.
- Erstelle für 2 Konten das Objektdiagramm und erfinde passende Werte.

- Individuelle Lösungen
Projekt erstellen und erste Implementationen
- Erstelle in BlueJ ein neues Projekt Bank und lege dort die Klasse Konto an.
- Füge die Attribute aus dem Klassendiagramm aus Aufgabe 1 entsprechend an den Anfang der Klasse ein.
- Implementiere folgende Methoden: (Die Methode verzinsen folgt später!)
- Konstruktor
- einzahlen, auszahlen
- setzeZinssatz, setzeDispozinssatz
- toString
public class Konto
{
private String kontoinhaber;
private String iban;
private double kapital;
private double zinssatz;
private double dispozinssatz;
public Konto(String kontoinhaber, String iban)
{
this.kontoinhaber = kontoinhaber;
kapital = 0.0;
this.iban = iban;
}
public void einzahlen(double betrag){
kapital += betrag;
}
public void abheben(double betrag){
kapital -= betrag;
}
public void setzeZinssatz(double zinssatz){
this.zinssatz = zinssatz;
}
public void setzeDispoZinssatz(double dispoZinssatz){
this.dispozinssatz = dispozinssatz;
}
public String toString(){
String antwort = String.format("IBAN: %10s, Kontoinhaber: %15s, kapital: %,15.2f €",kontoinhaber, iban, kapital);
return antwort;
}
}
Zinsrechnung
Die Verzinsung des Kapitals ist ein wesentlicher Teil des Geschäfts einer Bank. Meist gibt es für positive und negative Kontostände unterschiedliche Zinssätze.
Beispiel:
Verzinsen
- Erweitere die Klasse Konto um die die Methode
public void zins(). Die Methode zins berechnet die passenden Zinsen. Dabei wird auch darauf geachtet, ob auf dem Konto das Kapital positiv oder negativ ist (Schulden) und dann der passende Zinssatz verwendet. Also bei 1000€ auf dem Konto mit einem Zinssatz von 1% soll es 10€ als Rückgabewert berechnen (\(1000\cdot\frac{1}{100}=10\)). Bei einem negativen Kontostand soll der Dispozinssatz verwendet werden. - Implementiere in der Klasse Konto die Methode
public void verzinsen(). Diese Methode erhöht das Kapital bzw. die Schulden um den jeweiligen Zins. Hinweis: Dies kann mithilfe der Methode zins sehr einfach implementiert werden!
public double zins(){
double zins = 0.0;
if(kapital > 0){
zins = kapital * zinssatz / 100.0;
}else{
zins = kapital * dispozinssatz / 100.0;
}
return zins;
}
public void verzinsen(){
kapital += zins();
}
Die Klasse Bank (v0.1)
- Implementiere eine Klasse Bank. Ein Objekt der Klasse Bank soll in einem Array mindestens 8 Konten verwalten. Diese Konten sollen zumindest jeweils eine eindeutige IBAN und Kontoinhaber haben!
- Implementiere in der Klasse Bank die Methode
public Konto sucheKonto(String gesuchteIban). Diese Methode sucht in dem Array konten nach der IBAN im Parameter. Wird die IBAN gefunden, so wird das Konto-Objekt zurückgegeben. Wird es nicht gefunden, so wird null zurückgegeben.
/**
* Die Klasse Bank verwaltet Konten.
*
* @author Tim Schellartz
* @version 30.01.2021
*/
public class Bank
{
Konto[] konten;
/**
* Konstruktor der Klasse Bank. Hier werden einige Objekte angelegt
*/
public Bank(){
konten = new Konto[8];
konten[0] = new Konto("Jana Türlich", "DE1001");
konten[0].setzeZinssatz(0.1);
konten[0].setzeDispoZinssatz(4);
konten[1] = new Konto("Ellen Bogen", "DE1002");
konten[2] = new Konto("Clara Fall", "DE1003");
konten[3] = new Konto("Han Dschuh", "DE1004");
konten[4] = new Konto("Peter Silie", "DE1005");
konten[5] = new Konto("Moe Tief", "DE1006");
konten[6] = new Konto("Tie Reks", "DE1007");
konten[7] = new Konto("Ali Gator", "DE1008");
}
/**
* Suche ein Konto anhand der IBAN.
* @param gesuchte Iban Diese Iban wird in dem konten-Array gesucht.
* @return Das gesuchte Konto-Objekt bzw. null falls die IBAN nicht gefunden wird.
*/
public Konto sucheKonto(String gesuchteIban){
for(int i=0;i < konten.length;i++){
Konto aktuell = konten[i];
if(gesuchteIban.equals(aktuell.getIBAN())){
return aktuell;
}
}
return null;
}
}
Die Klasse Bank
In der vorherigen Aufgabe hast du bereits ein Grundgerüst einer Bank Klasse erstellt. Die Klasse soll nun um einige weitere Methoden erweitert werden. Da viele Methode auf allen Objekten des Konten Arrays arbeiten wird nun eine abgewandelte Version der for-Schleife eingeführt.
for-each-Schleife
Die for-each Schleife ist eine andere Schreibweise für die for-Schleife. Zunächst machen wir uns den Unterschied an einem Beispiel klar:
Kontosuche mit normaler for-Schleife
public Konto sucheKonto(String gesuchteIban){
for(int i=0;i < konten.length;i++){
Konto aktuell = konten[i];
if(gesuchteIban.equals(aktuell.getIBAN())){
return aktuell;
}
}
return null;
}
Kontosuche mit for-each-Schleife
public Konto sucheKontoForEach(String gesuchteIban){
for(Konto aktuell : konten){
if(gesuchteIban.equals(aktuell.getIBAN())){
return aktuell;
}
}
return null;
}
Bei der for-each-Schleife wird die Variable aktuell nach jedem Durchlauf durch den nächsten Eintrag (Objekte der Klasse Konto) im Array konten ersetzt. So wird jedes Objekt durchlaufen, aber du brauchst keine Indizes.
Beide Programme machen exakt dasselbe und keine Variante ist wirklich besser als die andere Variante. Allerdings ist die for-each-Schleife leichter lesbar als die normale Schleife und oft braucht man sowieso jedes Element eines Arrays um es zu überprüfen, zu zählen oder was auch immer. Aber Achtung: Falls du Elemente löschen willst, oder willst das 2 Elemente im Array die Position tauschen, so brauchst du den Index. Dies geht also nur mit der normalen Variante.
Der generelle Aufbau
Dokumentation der Klasse Bank
| Konstruktor |
Konstruktor der Klasse Bank. Hier werden einige Objekte angelegt. (Schon implementiert in letzter Aufgabe) |
|---|---|
| Anfrage |
Suche ein Konto anhand der IBAN und gib dies zurück. Gib null zurück falls es nicht gefunden wird. (ebenfalls bereits implementiert) |
| Auftrag |
Überweist den Betrag von dem Konto mit der IBAN vonIBAN auf das Konto mit IBAN zuIBAN. Ist der Betrag negativ, so soll nichts passieren und eine Fehlermeldung ausgegeben werden (in der Konsole) um möglich Fehleingaben zu vermeiden. |
| Auftrag |
Zum Jahresende wird das Kapital bzw. die Schulden jedes Kontos verzinst. Dabei werden die jeweils passenden Konditionen verwendet. |
| Anfrage |
Berechnet die Summe aller Kontostände im konten Array |
| Anfrage |
Berechnet den Durchschnitt aller Kontostände im konten Array |
| Anfrage |
Liefert als Rückgabe das Konto mit dem höchsten Kontostand |
| Anfrage |
Liefert als Rückgabe das Konto mit dem kleinsten Kontostand |
| Anfrage |
Liefert die Anzahl der Konten mit Schulden zurück. Gibt es also 2 Konten, die einen Kontostand unter 0 haben, so wird 2 zurück geliefert. |
| Anfrage |
Liefert als Antwort eine Array, welches nur die Konten mit Schulden enthält. Hinweis: Verwende die Methode getAnzahlKontenMitSchulden() als Hilfe. |
Implementation Bank
Implementiere alle in der Dokumentation erwähnten Methoden der Klasse Bank. Der Schwierigkeitsgrad steigt von oben nach unten leicht an. Bereits implementierte Methoden können und sollen verwendet werden.
Hinweis: Bei allen Methoden kann die for-each-Schleife sinnvoll eingesetzt werden, aber du darfst auch mit der normalen Schleife arbeiten.
/**
* Die Klasse Bank verwaltet Konten.
*
* @author Tim Schellartz
* @version 30.01.2021
*/
public class Bank
{
Konto[] konten;
/**
* Konstruktor der Klasse Bank. Hier werden einige Objekte angelegt.
*/
public Bank(){
konten = new Konto[8];
konten[0] = new Konto("Jana Türlich", "DE1001");
konten[0].setzeZinssatz(0.1);
konten[0].setzeDispoZinssatz(4);
konten[0].einzahlen(1000);
konten[1] = new Konto("Ellen Bogen", "DE1002");
konten[1].einzahlen(2000);
konten[2] = new Konto("Clara Fall", "DE1003");
konten[2].einzahlen(1234.56);
konten[3] = new Konto("Han Dschuh", "DE1004");
konten[3].einzahlen(3.14159);
konten[4] = new Konto("Peter Silie", "DE1005");
konten[4].einzahlen(2507.19);
konten[5] = new Konto("Moe Tief", "DE1006");
konten[5].einzahlen(-1803.87);
konten[6] = new Konto("Tie Reks", "DE1007");
konten[6].einzahlen(-20.11);
konten[7] = new Konto("Ali Gator", "DE1008");
}
/**
* Suche ein Konto anhand der IBAN und gib dies zurück.
* Gib null zurück falls es nicht gefunden wird.
* @param gesuchte Iban Diese Iban wird in dem konten-Array gesucht.
* @return Das gesuchte Konto-Objekt bzw. null falls die IBAN nicht gefunden wird.
*/
public Konto sucheKonto(String gesuchteIban){
for(int i=0;i < konten.length;i++){
Konto aktuell = konten[i];
if(gesuchteIban.equals(aktuell.getIBAN())){
return aktuell;
}
}
return null;
}
/**
* Überweist den Betrag von dem Konto mit der IBAN vonIBAN
* auf das Konto mit IBAN zuIBAN.
* Ist der Betrag negativ, so soll nichts passieren und
* eine Fehlermeldung ausgegeben werden (in der Konsole)
* um möglich Fehleingaben zu vermeiden.
* @param vonIBAN IBAN des Kontos, welches das Geld versendet.
* @param zuIBAN IBAN des Kontos, welches das Geld erhält.
* @param betrag Der Betrag.
*/
public void überweisen(String vonIBAN, String zuIBAN, double betrag){
if(betrag>=0){
Konto von = sucheKonto(vonIBAN);
Konto zu = sucheKonto(zuIBAN);
von.abheben(betrag);
zu.einzahlen(betrag);
}else{
System.err.println("Betrag negativ. Überweisung gestoppt!");
}
}
/**
* Zum Jahresende wird das Kapital bzw. die Schulden jedes Kontos verzinst.
* Dabei werden die jeweils passenden Konditionen verwendet.
*/
public void jahreswechsel(){
for(Konto k : konten){
k.verzinsen();
}
}
/**
* Berechnet die Summe aller Kontostände im konten Array
*/
public double kontoständeSumme(){
double sum = 0;
for(Konto k : konten){
sum += k.getKapital();
}
return sum;
}
/**
* Berechnet den Durschnitt aller Kontostände im konten Array
*/
public double kontoständeDurchschnitt(){
return kontoständeSumme()/konten.length;
}
/**
* Liefert als Rückgabe das Konto mit dem höchsten Kontostand
*/
public Konto kontoMax(){
Konto currentMax = konten[0]; // Setze ein beliebige Konto als aktuelle Maximum
// Überprüfe nun jedes Konto und ersetze das aktuelle Maximum bei Bedarf
for(Konto k : konten){
if(k.getKapital() > currentMax.getKapital()){
currentMax = k;
}
}
// Nun ist das aktuelle Maximum das gesamte Maximum.
return currentMax;
}
/**
* Liefert als Rückgabe das Konto mit dem kleinsten Kontostand
*/
public Konto kontoMin(){
Konto currentMin = konten[0]; // Setze ein beliebige Konto als aktuelle Minimum
// Überprüfe nun jedes Konto und ersetze das aktuelle Minimum bei Bedarf
for(Konto k : konten){
if(k.getKapital() < currentMin.getKapital()){
currentMin = k;
}
}
// Nun ist das aktuelle Minimum das gesamte Minimum.
return currentMin;
}
/**
* Liefert die Anzahl der Konten mit Schulden zurück.
* Gibt es also 2 Konten, die einen Kontostand unter 0 haben,
* so wird 2 zurück geliefert.
*/
public int getAnzahlKontenMitSchulden(){
int anzahl = 0;
for(Konto k : konten){
if(k.getKapital() < 0){
anzahl++;
}
}
return anzahl;
}
/**
* Liefert als Antwort eine Array, welches nur die Konten mit Schulden enthält.
* Hinweis: Verwende die Methode getAnzahlKontenMitSchulden() als Hilfe.
*/
public Konto[] getKontenMitSchulden(){
Konto[] schuldner = new Konto[getAnzahlKontenMitSchulden()];
int i = 0;
for(Konto k : konten){
if(k.getKapital() < 0){
schuldner[i] = k;
i++;
}
}
return schuldner;
}
}
Kredite
Auftragseingang der Erkabank
Die Erkabank ist mit den bisherigen Lösungen sehr zufrieden. Daher erreicht dich folgende Nachricht als Folgeauftrag:
Sehr geehrte Damen und Herren,
ihre bisherigen Umsetzungen sind vielversprechend und wir sind insgesamt von einer weiteren Zusammenarbeit überzeugt.
Im folgenden beschreiben wir unsere Anforderungen an eine weitere Klasse Kredit.
- Jeder Kredit hat einen Kreditnehmer (Name), einen Betrag, einen Zinssatz und eine festgelegte, jährliche Rate.
- Die jährliche Rate und der Zinssatz sollen sich jederzeit durch einen Mitarbeiter der Bank anpassen lassen.
- Der aktuelle Zins für dieses Jahr wird genauso berechnet wie bei den Konten. Diese Implementation sollte für sie also kein Problem darstellen.
- Zudem soll es auch hier eine Methode geben, welche wir zum Jahreswechsel aufrufen können um die Kreditsumme anzupassen. Am Jahresende wird der Zinssatz berechnet. Von der festgelegten Rate muss dann dieser Zins abgezogen werden und der übrig gebliebene Teil, die Tilgung, wird dann vom Kreditbetrag abgezogen.
- Ferner wollen wir unseren Kunden vor ab einen Tilgungsplan berechnen lassen. Dieser stell die Kreditenwicklung über die Jahre dar, bis der Kredit vollständig abgezahlt. Da dies nur eine Vorschau ist, soll nicht der aktuelle Kreditbetrag angepasst werden.
Mit freundlichen Grüßen
Erkabank
Implementationsdiagramm erstellen
- Erstelle anhand des Auftrags ein Klassendiagramm für die Klasse Kredit.
- Erstelle für 2 Konten das Objektdiagramm und erfinde passende Werte.

- Individuelle Lösungen
Kredite
Eine Bank verleiht Geld an Personen oder Unternehmen. Dieser Personen (Kreditnehmer) nehmen also einen Kredit bei einer Bank auf. Die Bank verschenkt allerdings nicht das Geld oder leiht es ohne Gegenleistung aus, sondern die Bank möchte hier durch Zinsen Einnahmen generieren. Für diesen Beispielkreditvertrag wird daher eine jährliche Rate vereinbart, zum Beispiel 10000€ pro Jahr und davon müssen die für den Kreditbetrag anfallenden Zinsen bezahlt werden. Erst der Rest der Rate fließt in die Abzahlung des Kredites. Dies nennt man Tilgung.Den folgenden Rechner kannst du verwenden, um dir einen Überblick zu verschaffen. Verwende verschiedene Einstellungen.
Implementation Klasse Kredit
Ergänze dein Bank Projekt um eine Klasse Kredit und implementiere alle geforderten Methoden (siehe auch Lösung vorherige Aufgabe).
Hinweis zur Methode printTilgungsplan(): Diese Methode ist mit Abstand die schwierigste. Das Ergebnis soll ähnlich zur obigen Tabelle aussehen. Allerdings ist die Formatierung als Tabelle schwierig. Daher kannst du dies einfach untereinander in der Konsole ausgeben:

/**
* Ein Kredit
*
* @author Tim Schellartz
* @version 16.02.2021
*/
public class Kredit
{
private String kreditnehmer;
private double betrag;
private double zinssatz;
private double rate;
/**
* Konstruktor
* Zinsatz ist standardmäßig 1.5%
*/
public Kredit(String pKreditnehmer, double pBetrag, double pRate)
{
kreditnehmer = pKreditnehmer;
betrag = pBetrag;
zinssatz = 1.5;
rate = pRate;
}
/**
* Setzt die jährliche Rate
*/
public void setzeRate(double pRate){
rate = pRate;
}
/**
* Setzt den Zinssatz
*/
public void setzeZinssatz(double pZinssatz){
zinssatz = pZinssatz;
}
/**
* Berechnet den aktuellen Jahreszins
*/
public double berechneZins(){
return betrag * zinssatz/100.0;
}
/**
* Der Kredit wird verzinst. Dieser Zins wird von der Jahresrate abgezogen.
* Der Rest, die Tilgung, wird von der Kreditsumme abgezogen.
*/
public void verzinsenUndTilgen(){
double zins = berechneZins();
double tilgung = rate - zins;
betrag = betrag-tilgung;
}
/**
* Als Vorschau gedacht.
* Die Kreditentwicklung über die Jahre bis zur Abzahlung werden übersichtlich in der
* Konsole ausgegeben.
*/
public void printTilgungsplan(){
double tempBetrag = betrag;
int jahr = 0;
double zinsGesamt=0, tilgungGesamt=0;
System.out.println(this);
System.out.printf("%4s %16s %16s %17s\n","Jahr", "Zins", "Tilgung", "Neuer Betrag");
while(tempBetrag > 0){
jahr++;
double zins = tempBetrag * zinssatz/100.0;
double tilgung = rate - zins;
if(rate < zins){
System.out.println("Tilgungsrate zu gering! Kreditvolumen wird zunehmen!");
break;
}
if(tempBetrag < tilgung){
tilgung = tempBetrag;
}
tempBetrag -= tilgung;
tilgungGesamt += tilgung;
zinsGesamt += zins;
System.out.printf("%4d %,15.2f€ %,15.2f€ %,16.2f€\n",jahr, zins, tilgung, tempBetrag);
}
System.out.println("--------------------------------------------------------");
System.out.printf("%4d %,15.2f€ %,15.2f€",jahr, zinsGesamt, tilgungGesamt);
}
/**
* Der Kredit wird mit den wesentlichen Daten in der Konsole ausgegeben.
*/
public String toString(){
String antwort = String.format("Kreditnehmer: %15s, Kredit: %,15.2f €", kreditnehmer, betrag);
return antwort;
}
}
Erweiterung Bank Klasse
Erweitere deine Klasse Bank um ein Array von Krediten. Dieses Array soll mindestens 4 verschiedene Kredite verwalten.
/**
* Die Klasse Bank verwaltet Konten.
*
* @author Tim Schellartz
* @version 16.02.2021
*/
public class Bank
{
Konto[] konten;
Kredit[] kredite;
/**
* Konstruktor der Klasse Bank. Hier werden einige Objekte angelegt.
*/
public Bank(){
konten = new Konto[8];
konten[0] = new Konto("Jana Türlich", "DE1001");
konten[0].setzeZinssatz(0.1);
konten[0].setzeDispoZinssatz(4);
konten[0].einzahlen(1000);
//... (gekürzt)
kredite = new Kredit[5];
kredite[0] = new Kredit("Andreas Kreuz", 150000,20000);
kredite[1] = new Kredit("Ted Tanus", 325000,50000);
kredite[2] = new Kredit("Tom Bola", 400000,30000);
kredite[2].setzeZinssatz(0.5);
kredite[3] = new Kredit("Stan Dard", 25000,5000);
kredite[4] = new Kredit("Roy Bär", 70000,15000);
}
//... (gekürzt)
}
Konten hinzufügen und löschen: Arrays stoßen an ihre Grenzen
Das Problem
Bei Verwendung der Software ist der Erkabank folgendes aufgefallen: Es ist nicht möglich neue Konten (oder Kredite, aber wir beschränken uns im Folgenden auf Konten) während das Programm läuft anzulegen. Dies ist aber sehr ungünstig für eine Bank, welche in der Lage sein muss neue Konten aufzunehmen oder alte zu löschen und nicht jedesmal den Quellcode anpassen kann und will.
Eins vorneweg: Arrays sind sehr schnell, einfach zu verwenden und aus diesen Gründen sehr weit verbreitet. Da sie aber eine feste Größe haben funktionieren sie nur dann so richtig gut, wenn die Datenmenge eher statisch ist. Das heißt, wenn sich die Objektsammlung im Array nicht zu schnell durch Hinzufügen oder Löschen ändert. Daher werden die folgenden Implementationen zum Hinzufügen und Löschen von Elementen im Array etwas komplizierter als man es vielleicht erwarten würde.
Ein kleiner Ausblick: Für eher dynamische Datenmengen, also wo häufig was hinzukommt oder gelöscht wird, gibt es natürlich auch spezielle Datenstrukturen: List, Queue, Stack, ArrayList usw. Aber die werden erst wesentlich später behandelt.
Ein Problem - mehrere Ideen
Das Hinzufügen und Löschen in einem Array kann im Grunde auf zwei verschiedenen Wegen implementiert werden:
| Variante 1: Löcher | Variante 2: Verschieben (engl. shift) |
|---|---|
|
Bei dieser Variante ist das Löschen sehr einfach: Wird ein Objekt gelöscht, so wird die Position im Array einfach durch null ersetzt. Dies geht sehr schnell. Allerdings führt dies zu "Löchern" im Array: Also Einträgen die null sind, obwohl danach noch sinnvolle Einträge kommen. Dies muss bei der Implementation JEDER weiteren Methode beachtet werden. Beispiel: Nehmen wir ein Array von Konten. Alle Einträge sind mit einem Konto initialisiert. Werden nun zum Beispiel die Konten an Index 2 und 5 gelöscht, so sieht das Array löchrig aus: Vorteile: Einfache Implementation, schnelles Löschen. Nachteile: Löcher führen zu längerer Suche (z.B. bei linearer Suche muss immer das ganze Array durchlaufen werden, selbst wenn nur wenige Konten enthalten sind) und die null-Elemente können zu Fehlern führen (null-Pointer-Exception). Dies muss irgendwie behandelt werden. |
Bei dieser Variante ist das Löschen zwar aufwendig, aber alle anderen Methoden schneller und weniger fehleranfällig. Die Idee ist, dass das Array immer ohne Löcher bleibt, indem beim Löschen die Lücke wieder aufgefüllt wird. Hier kann man verschiedene Ansätze verfolgen, wir verschieben dazu den Inhalt des Arrays so dass die Lücke geschlossen bleibt. Beispiel: Nehmen wir ein Array von Konten. Alle Einträge sind mit einem Konto initialisiert. Das Löschen des Kontos an Index 2 verschiebt alle anderen Konten um eine Stelle nach vorne. Der letzte Eintrag wird dann ebenfalls auf null gesetzt: Vorteile: Keine Löcher, Array bleibt kompakt und kann daher schnell durchlaufen werden. Nachteile: Löschen sehr aufwendig, da viele Elemente verschoben werden müssen. Dies kann theoretisch dadurch umgangen werden, dass einfach das letzte Element an die Lücke rutscht, aber dann ändert sich immer die Sortierung des Arrays. |
Insgesamt ist Variante 2 besser. Da wir aber schon viel implementiert haben und die Anpassungen bei Variante 1 weniger sind, verwenden wir der Einfachheit halber die Variante 1. Auf jeden Fall musst du nahezu jede Methode anpassen um die null-Elemente zu überspringen. Beispiel für suche Konto:
public Konto sucheKonto(String gesuchteIban){
for(Konto aktuell:konten){
if(aktuell != null && gesuchteIban.equals(aktuell.getIBAN())){
return aktuell;
}
}
return null;
}
Der Zusatz von aktuell != null überspringt die null Elemente. Im Grunde musst du dies in jeder Methode überprüfen!
Hinzufügen von Konten
Da Arrays eine feste Größe haben ist das Hinzufügen neuer Konten im Grunde schwierig. Daher muss das Array bei Initialisierung mehr Plätze haben als Konten. Die anderen Objekte bleiben dann null und werden erst zur Laufzeit durch ein Objekt ersetzt. Dies funktioniert zwar, ist aber ungünstig, da der Speicher für die leeren Arrayplätze dauerhaft reserviert ist.
Hinzufügen von Konten
Ändere die Klasse Bank so ab, dass bis zu 1000 Konten aufgenommen werden können und Konten während der Laufzeit mit der Methode public void addKonto(String inhaber, String iban) hinzugefügt werden können. Beachte dabei auch, dass die IBAN eindeutig sein muss. Gib bei einer doppelten IBAN eine Fehlermeldung aus und füge nicht hinzu!
/**
* Die Klasse Bank verwaltet Konten.
*
* @author Tim Schellartz
* @version 16.02.2021
*/
public class Bank
{
private Konto[] konten;
private Kredit[] kredite;
/**
* Konstruktor der Klasse Bank. Hier werden einige Objekte angelegt.
*/
public Bank(){
konten = new Konto[1000];
addKonto("Jana Türlich", "DE1001");
konten[0].setzeZinssatz(0.1);
konten[0].setzeDispoZinssatz(4);
konten[0].einzahlen(1000);
addKonto("Ellen Bogen", "DE1002");
konten[1].einzahlen(2000);
addKonto("Clara Fall", "DE1003");
konten[2].einzahlen(1234.56);
addKonto("Han Dschuh", "DE1004");
konten[3].einzahlen(3.14159);
addKonto("Peter Silie", "DE1005");
konten[4].einzahlen(2507.19);
addKonto("Moe Tief", "DE1006");
konten[5].einzahlen(-1803.87);
addKonto("Tie Reks", "DE1007");
konten[6].einzahlen(-20.11);
addKonto("Ali Gator", "DE1008");
kredite = new Kredit[5];
kredite[0] = new Kredit("Andreas Kreuz", 150000,20000);
kredite[1] = new Kredit("Ted Tanus", 325000,50000);
kredite[2] = new Kredit("Tom Bola", 400000,30000);
kredite[2].setzeZinssatz(0.5);
kredite[3] = new Kredit("Stan Dard", 25000,5000);
kredite[4] = new Kredit("Roy Bär", 70000,15000);
}
/**
* Suche ein Konto anhand der IBAN und gib dies zurück.
* Gib null zurück falls es nicht gefunden wird.
* @param gesuchte Iban Diese Iban wird in dem konten-Array gesucht.
* @return Das gesuchte Konto-Objekt bzw. null falls die IBAN nicht gefunden wird.
*/
public Konto sucheKonto(String gesuchteIban){
for(Konto aktuell:konten){
if(aktuell != null && gesuchteIban.equals(aktuell.getIBAN())){
return aktuell;
}
}
return null;
}
/**
* Überweist den Betrag von dem Konto mit der IBAN vonIBAN
* auf das Konto mit IBAN zuIBAN.
* Ist der Betrag negativ, so soll nichts passieren und
* eine Fehlermeldung ausgegeben werden (in der Konsole)
* um möglich Fehleingaben zu vermeiden.
* @param vonIBAN IBAN des Kontos, welches das Geld versendet.
* @param zuIBAN IBAN des Kontos, welches das Geld erhält.
* @param betrag Der Betrag.
*/
public void überweisen(String vonIBAN, String zuIBAN, double betrag){
if(betrag>=0){
Konto von = sucheKonto(vonIBAN);
Konto zu = sucheKonto(zuIBAN);
von.abheben(betrag);
zu.einzahlen(betrag);
}else{
System.err.println("Betrag negativ. Überweisung gestoppt!");
}
}
/**
* Zum Jahresende wird das Kapital bzw. die Schulden jedes Kontos verzinst.
* Dabei werden die jeweils passenden Konditionen verwendet.
*/
public void jahreswechsel(){
for(Konto k:konten){
if(k!=null){
k.verzinsen();
}
}
}
/**
* Berechnet die Summe aller Kontostände im konten Array
*/
public double kontoständeSumme(){
double sum = 0;
for(Konto k:konten){
if(k!=null){
sum += k.getKapital();
}
}
return sum;
}
/**
* Berechnet den Durschnitt aller Kontostände im konten Array
*/
public double kontoständeDurchschnitt(){
int n = 0;
for(Konto k:konten){
if(k!=null){
n++;
}
}
return kontoständeSumme()/n;
}
/**
* Liefert als Rückgabe das Konto mit dem höchsten Kontostand
*/
public Konto kontoMax(){
Konto currentMax = konten[0]; // Setze ein beliebige Konto als aktuelle Maximum
// Überprüfe nun jedes Konto und ersetze das aktuelle Maximum bei Bedarf
for(Konto k:konten){
if(k!=null && k.getKapital() > currentMax.getKapital()){
currentMax = k;
}
}
// Nun ist das aktuelle Maximum das gesamte Maximum.
return currentMax;
}
/**
* Liefert als Rückgabe das Konto mit dem kleinsten Kontostand
*/
public Konto kontoMin(){
Konto currentMin = konten[0]; // Setze ein beliebige Konto als aktuelle Minimum
// Überprüfe nun jedes Konto und ersetze das aktuelle Minimum bei Bedarf
for(Konto k:konten){
if(k!=null && k.getKapital() < currentMin.getKapital()){
currentMin = k;
}
}
// Nun ist das aktuelle Minimum das gesamte Minimum.
return currentMin;
}
/**
* Liefert die Anzahl der Konten mit Schulden zurück.
* Gibt es also 2 Konten, die einen Kontostand unter 0 haben,
* so wird 2 zurück geliefert.
*/
public int getAnzahlKontenMitSchulden(){
int anzahl = 0;
for(Konto k:konten){
if(k!=null && k.getKapital() < 0){
anzahl++;
}
}
return anzahl;
}
/**
* Liefert als Antwort eine Array, welches nur die Konten mit Schulden enthält.
* Hinweis: Verwende die Methode getAnzahlKontenMitSchulden() als Hilfe.
*/
public Konto[] getKontenMitSchulden(){
Konto[] schuldner = new Konto[getAnzahlKontenMitSchulden()];
int j = 0;
for(Konto k:konten){
if(k!=null && k.getKapital() < 0){
schuldner[j] = k;
j++;
}
}
return schuldner;
}
/**
* Fügt ein Konto an die erste freie Stelle hinzu
* Parameter sind der Name des Kontoinhaber sowie eine IBAN
*/
public void addKonto(String inhaber, String iban){
if(sucheKonto(iban)!=null){
System.err.println("IBAN wird schon verwendet. Bitte erneut mit neuer IBAN versuchen!");
}else{
for(int i=0;i < konten.length;i++){
if(konten[i]==null){
konten[i] = new Konto(inhaber, iban);
return;
}
}
System.err.println("Array ist voll! Bitte Programmierer anrufen ;)");
}
}
}
Das Löschen von Elementen in einem Array
Das Löschen von Elementen in einem Array besteht aus 2 Schritten:
- Suche den Index an dem das zu löschende Element liegt.
- Ersetze diese Stelle durch null.
Löschen
Implementiere die Methode removeKonto(String iban), welche das Konto mit der übergebenen IBAN entfernt.
public void removeKonto(String iban){
for(int i=0;i < konten.length;i++){
if(konten[i]!=null && konten[i].getIBAN().equals(iban)){
konten[i] = null;
return;
}
}
}
Zusammenfassung
Der Vorteil von Arrays ist die hohe Zugriffsgeschwindigkeit, da die Objekte im Array direkt über den Index angesprochen werden können.
Der Nachteil ist hingegen, dass das hinzufügen und löschen nicht einfach zu realisieren ist.
Alternativen, für dynamische Datenmengen (also häufig hinzugefügt und gelöscht):
- List Zwar langsamer, aber hinzufügen etc. vorprogrammiert.
- ArrayList Kombiniert beide Idee und ist damit für normale Anwender häufig die beste Wahl. Direkter Zugriff per Index und das Hinzufügen und Löschen sind bereits vorprogrammiert. Da die ArrayList aber im Grunde ein Array mit passenden Methoden ist, ist das Hinzufügen und Löschen teilweise aufwendig (im Sinne der Komplexität bzw. Laufzeit). Besonders wenn das Array voll ist, wird im Grunde ein größeres Array angelegt und das alte dort reinkopiert. Also bei sehr zeitkritischen Prozessen muss man wieder auf das gute alte Array zurückgreifen.
Benutzeroberfläche
Wiederholung Scanner
Nicht jeder Benutzer ist in der Lage mit BlueJ zu arbeiten. Daher ist die Erstellung einer Benutzeroberfläche in diesem Fall sinnvoll. Zur Vereinfachung läuft diese Benutzeroberfläche nur in der Konsole. Ein Beispiel siehst du hier:
Scanner Klasse
Die Klasse Scanner kann von dir verwendet werden um Text innerhalb der Konsole einzulesen. Dazu musst du 3 Schritte durchführen:
- Importiere die Klasse aus den Java-Paketen. Schreibe dazu
import java.util.Scanner;ganz an den Anfang der Datei, noch außerhalb der Klassendefinition. - Da man meist mehrere Dinge aus der Konsole auslesen möchte bietet es sich an den Scanner innerhalb Klasse als Attribut mit
Scanner sc = new Scanner(System.in)zu deklarieren und zu initialisieren. - Anschließend kannst du innerhalb dieser Klasse den Scanner mittels
sc.nextLine()eine Zeile einlesen lassen. Dies liefert einen String als Rückgabewert.
Beispiel:
import java.util.Scanner;
/**
* Eine einfache Klasse mit Scanner
*/
public class EineKlasse{
Scanner sc = new Scanner(System.in);
/**
* Liest den Namen einer Person ein und begrüßt diese
*/
public void eineMethode(){
String name = sc.nextLine();
System.out.println("Hallo " + name);
}
}
Implementation Benutzeroberfläche
Implementiere eine Klasse UI, welche eine einfache Benutzeroberfläche simuliert. Implementiere mindestens 4 Methoden (wie einzahlen, auszahlen, usw.) und achte dabei auf Fehlermeldungen, zum Beispiel wenn eine IBAN nicht vorhanden ist etc.
import java.util.Scanner;
/**
* Write a description of class UI here.
*
* @author Tim Schellartz
* @version 17.02.2021
*/
public class UI
{
Bank bank;
Scanner sc = new Scanner(System.in);
public UI(){
bank = new Bank();
}
public void hauptmenü(){
int eingabe = 0;
while(eingabe != -1){
System.out.println("---=== Hauptmenü ===---");
System.out.println("(1) Kontenübersicht");
System.out.println("(2) Kontodetails");
System.out.println("(3) Einzahlung");
System.out.println("(4) Auszahlung");
System.out.println("(5) Überweisung");
System.out.println("(6) Konto hinzufügen");
System.out.println("(7) Konto löschen");
System.out.println("(-1) Ende");
System.out.print("Eingabe : ");
eingabe = Integer.parseInt(sc.nextLine());
if(eingabe == 1){
kontenübersicht();
}else if (eingabe ==2){
kontodetails();
}else if(eingabe == 3){
einzahlung();
}else if(eingabe == 4){
abhebung();
}else if(eingabe == 5){
uberweisung();
}else if(eingabe == 6){
hinzufügen();
}else if(eingabe == 7){
löschen();
}else if(eingabe == -1){
System.out.println("Ende");
}else{
System.out.println("Eingabe nicht korrekt! Bitte erneut eingeben.");
}
}
}
/**
* Eine Kontenübersicht wird ausgegeben
*/
public void kontenübersicht(){
System.out.println(bank);
}
public void kontodetails(){
System.out.print("Geben Sie die IBAN ein: ");
String iban = sc.nextLine();
Konto k = bank.sucheKonto(iban);
if(k!=null){
System.out.println(k);
}else{
System.out.println("IBAN nicht vorhanden");
}
}
/**
* Eine Einzahlung wird vorgenommen
*/
public void einzahlung(){
System.out.print("Geben Sie die IBAN ein: ");
String iban = sc.nextLine();
Konto k = bank.sucheKonto(iban);
System.out.print("Geben Sie den Einzahlungsbetrag ein: ");
double betrag = Double.parseDouble(sc.nextLine());
if(k!=null && betrag>0){
k.einzahlen(betrag);
}else{
System.out.println("Einzahlung nicht möglich. Die IBAN wurde nicht gefunden oder der Betrag ist negativ.");
}
}
/**
* Geld abheben
*/
public void abhebung(){
System.out.print("Geben Sie die IBAN ein: ");
String iban = sc.nextLine();
Konto k = bank.sucheKonto(iban);
System.out.print("Geben Sie den abzuhebenden Betrag ein: ");
double betrag = Double.parseDouble(sc.nextLine());
if(k!=null && betrag>0){
k.abheben(betrag);
}else{
System.out.println("Abhebung nicht möglich. Die IBAN wurde nicht gefunden oder der Betrag ist negativ.");
}
}
/**
* Eine Überweisung innerhalb einer Bank. Daher können die internen Kontonummer, also die Indizes des Arrays verwendet werden.
*/
public void uberweisung(){
System.out.print("Geben Sie die IBAN des Absenders ein: ");
String vonIBAN = sc.nextLine();
Konto vonKonto = bank.sucheKonto(vonIBAN);
System.out.print("Geben Sie die IBAN des Empfängers ein: ");
String zuIBAN = sc.nextLine();
Konto zuKonto = bank.sucheKonto(zuIBAN);
System.out.print("Geben Sie den Überweisungsbetrag ein: ");
double betrag = Double.parseDouble(sc.nextLine());
if(vonKonto!=null && zuKonto!=null && betrag>0){
bank.überweisen(vonIBAN,zuIBAN, betrag);
}else{
System.out.println("Überweisung nicht möglich. Die IBAN wurde nicht gefunden oder der Betrag ist negativ.");
}
}
public void hinzufügen(){
System.out.print("Geben Sie die IBAN des neuen Kontos ein: ");
String iban = sc.nextLine();
System.out.print("Geben Sie den Namen des Kontoinhabers ein: ");
String name = sc.nextLine();
bank.addKonto(name, iban);
}
public void löschen(){
System.out.print("Geben Sie die IBAN des zu löschenden Kontos ein: ");
String iban = sc.nextLine();
bank.removeKonto(iban);
}
public static void main(String[] args){
UI ui = new UI();
ui.hauptmenü();
}
}
Zum Weiterarbeiten: Speichern und grafische Benutzeroberfläche (GUI)
Speichern und laden von Dateien
Das Speichern und laden von Dateien in Java ist leider nicht ganz einfach geraten, aber auch nicht auf dem Lehrplan NRW enthalten. Es gibt dazu recht viele gute Anleitungen im Internet, zum Beispiel hier. Daher nur die wesentlichen Schritte:
- Alle zu speichernden Klassen müssen das Interface java.io.Serializable implementieren. Dabei musst du nur den Zusatz angeben, das Interface verlangt keine Methode.
- Anschließend kannst du die Objekte der Klasse speichern und laden und brauchst dich nicht um Umwandlung in Text etc. zu kümmern.
Grafische Benutzeroberfläche
Eine grafische Benutzeroberfläche wäre natürlich noch wesentlich praktischer und hübscher als unsere Benutzeroberfläche. Allerdings ist deren Implementation nicht ganz einfach und tatsächlich im Zusammenhang mit Java auch ein problematisches Thema. Es gibt bewährte aber veraltete Benutzeroberflächen (AWT, Swing) oder modernere aber nicht endgültig in Java aufgenommene Oberflächen (JavaFX). Also keine optimale, direkt von Java bereitgestellte Lösung. Daher nur der Tipp: Unsere Banking-Software ist so implementiert, dass du diese direkt in eine grafische Benutzeroberfläche überführen kannst. Als einfachen Startpunkt empfehle ich Netbeans. Da kannst du einfach Oberflächen zusammenbasteln.