252-0027
Einführung in die Programmierung
7.0 Arbeiten mit Objekten und Klassen
Thomas R. Gross
Department Informatik ETH Zürich
Copyright (c) Pearson 2013. and Thomas Gross 2016 All rights reserved.
Uebersicht
7.1 Initialisierung
§ Variable in Methoden
§ Variable (Attribute) in Klassen
7.2 Listen als Beispiel
§ Warum kopieren wir in einem Program Referenzen auf Objekte oder Arrays?
Copyright (c) Pearson 2013 and Thomas Gross 2016.
All rights reserved. 2
Eine Klasse für Knoten einer Liste
public class ListNode { int data;
ListNode next;
§ Jeder Knoten der Liste speichert:
}§ Den Wert einer ganzen (int) Zahl
§ Einen Verweis auf einen anderen Listenknoten
§ ListNodes können zu einer Kette verbunden (“linked”) wer- den um eine Menge oder Liste von Werten zu speichern.
data next 42
data next -3
data next 17
data next 9 null
5
Probleme
§ Wie könnten wir den Knoten an Anfang entfernen?
int top = list.removeFront(); //??
§ Gewünscht:
§ Entfernen ist einfach aber wie kann die Referenzvariable list auf das (neue) erste Element verweisen?
6
data next 10
data next
list 20 data next
40
list data next
20
data next 40
Probleme
§ Was passiert wenn wir eine beliebige Referenzvariable current verwenden?
int someValue = current.removeFront(); //??
§ Gewünscht:
§ Aber wie erreichen wir den Vorgängerknoten?
7data next 10
data next
list 20 data next
40
list data next 10
data next 40
current
Eine Klasse LinkedIntList
§ ListNodes sollen nicht von Klienten direkt verändert werden.
§ Also entwickeln wir eine Klasse die die Knoten versteckt:
LinkedIntList.
front LinkedIntList
ListNode ListNode ListNode
data next 42
data next -3
data next 17
Eine Klasse LinkedIntList
§ Klienten arbeiten mit LinkedIntList, nicht mit ListNode Objekten.
§ Wir können die Elemente numerieren (von 0 an)
front LinkedIntList
ListNode ListNode ListNode
data next 42
data next -3
data next 17
element 0 element 1 element 2
§ Hat die Methoden:
§ add, get, indexOf, remove, size, toString
§ Die Liste ist als Kette von Knoten intern implementiert
§ Das LinkedIntList Objekt enthält eine Referenz auf das erste Element in front
§ null im next Attribut signalisiert Ende der Liste
§ Hat front den Wert null so ist die Liste leer
front add(value)
add(index, value) indexOf(value) remove(index) size()
toString() LinkedIntList
ListNode ListNode ListNode
data next 42
data next -3
data next 17
element 0 element 1 element 2
LinkedIntList Klasse v1
public class LinkedIntList { private ListNode front;
public LinkedIntList() { front = null;
}
// methods }
front = LinkedIntList
Die add Methode
// Adds the given value to the end of the list.
public void add(int value) { ...
}
§ Wie wollen wir einen neuen Knoten am Ende hinzufügen?
§ Sind die Werte in der Liste vor diesem Schritt wichtig?
front =
data next 42
data next -3
data next 17
element 0 element 1 element 2
Ein Element in eine leere Liste hinzufügen
§ Bevor 20 hinzugefügt wird: Danach:
§ Wir müssen einen Knoten erstellen und an die Liste anhängen.
front = front =
data next 20
element 0
Die add Methode, 1. Versuch
// Adds the given value to the end of the list.
public void add(int value) { if (front == null) {
// adding to an empty list front = new ListNode(value);
} else {
// adding to the end of an existing list
...
} }
§ Bevor 20 am Ende hinzugefügt wird :
§ Danach:
front =
data next 42
data next -3
front =
data next 42
data next 20
element 0 element 2
element 0 element 1
An eine nicht-leere Liste anhängen
data next -3
element 1
data next -3
Vorsicht an der Kante!
§ Um ein Element zur Liste hinzuzufügen (oder zu von der Liste zu entfernen) müssen wir das next Attribut des vorherigen Knotens modifizieren.
§ Wie durchlaufen wir eine Liste?
§ Was für einen Typ muss current haben? ListNode
front =
data next 42
element 0 element 1
data next -3
Vorsicht an der Kante!
§ Um ein Element zur Liste hinzuzufügen (oder zu von der Liste zu entfernen) müssen wir das next Attribut des vorherigen Knotens modifizieren.
§ Worauf sollte current verweisen wenn wir 20 am Ende einfügen wollen?
§ Welcher Loop Test lässt uns an dieser Stelle anhalten?
front =
data next 42
element 0 element 1
Die add Methode
// Adds the given value to the end of the list.
public void add(int value) { if (front == null) {
// adding to an empty list front = new ListNode(value);
} else {
// adding to the end of an existing list ListNode current = front;
while (current.next != null) { current = current.next;
}
current.next = new ListNode(value);
} }
Implementation von get
// Returns value in list at given index.
// 0 <= index < size()
public int get(int index) { ...
}
§ Implementieren Sie die get Methode.
front =
data next 42
data next -3
data next 17
element 0 element 1 element 2
Die get Methode
// Returns value in list at given index.
// 0 <= index < size()
public int get(int index) { ListNode current = front;
for (int i = 0; i < index; i++) { current = current.next;
}
return current.data;
}
Implementation von add (index)
// Inserts the given value at the given index.
public void add(int index, int value) { ...
}
§ Implementieren Sie diese Variante der add Methode.
front =
data next 42
data next -3
data next 17
element 0 element 1 element 2
Die 2. Variante der add Methode
// Inserts the given value at the given index.
// 0 <= index <= size()
public void add(int index, int value) { if (index == 0) {
// adding to an empty list
front = new ListNode(value, front);
} else {
// inserting into an existing list ListNode current = front;
for (int i = 0; i < index - 1; i++) { current = current.next;
}current.next = new ListNode(value, current.next);
} }
Element entfernen: remove
// Removes and returns the list's first value.
public int remove() { ...
}
§ Wie entfernt man den ersten Knoten einer Liste?
§ Ist der Inhalt der Liste wichtig wenn wir den ersten Knoten entfernen wollen?
Entfernen des ersten Elements
§ Vor dem Entfernen des ersten Elements:
§ Nachdem ein Element entfernt wurde: Nachdem 2 Elemente … :
front =
data next 20
front =
data next 42
data next 20
element 0 element 1
element 0
front =
remove Methode
// Removes and returns the first value.
// List must not be empty.
public int remove() {
if (front == null) { System.exit(-1);
}
int result = front.data;
front = front.next;
return result }
Eine weitere remove Methode
// Removes value at given index from list.
// Precondition: 0 <= index < size public void remove(int index) {
...
}
§ Wie können wir ein beliebiges Element der Liste entfernen?
§ Ist der Inhalt der Liste wichtig wenn wir einen Knoten entfernen wollen?
Entfernen eines Elementes
§ Vor dem Entfernen des Elements mit Index 1:
§ Danach:
front =
data next 20
front =
data next 42
data next -3
data next 20
element 0 element 1 element 2
element 0 element 1
data next 42
Entfernen des Elements mit Index 0
§ Vor Entfernen des Elements mit Index 0:
§ Danach:
front =
data next -3
data next 20
front =
data next 42
data next -3
data next 20
element 0 element 1 element 2
element 0 element 1
Entfernen des einzigen Elementes
§ Davor: Danach:
§ Wir müssen das front Attribut auf null setzen (so dass es nicht auf einen ListNode verweist)
§ Ist das ein Sonderfall den wir im Programm behandeln müssen?
front front =
data next 20
element 0
remove Methode (Variante 2)
// Removes value at given index from list.
// Precondition: 0 <= index < size() public void remove(int index) {
if (index == 0) {
// special case: removing first element front = front.next;
} else {
// removing from elsewhere in the list ListNode current = front;
for (int i = 0; i < index - 1; i++) { current = current.next;
}current.next = current.next.next;
} }
LinkedIntList Klasse v2
public class LinkedIntList { private ListNode front;
public LinkedIntList() { front = null;
}
public void add (int value) { … }
public void add (int index, int value) { … } public void remove() { … }
public void remove(int index) { … } }
front = LinkedIntList
Namen von Methoden
§ In einer Klasse können verschiedene Methoden den selben Namen haben
public void add (int value) { … }
public void add (int index, int value) { … }
§ Die Typen der Parameter müssen unterschiedlich sein
public void add (int value) { … }
public void add (int index) { … } // not OK
35
36
String
toString muss natuerlich einen String zurueckgeben!
Uebung
§ Schreiben Sie eine Methode addSorted die den Wert einer ganzen Zahl als Parameter akzeptiert und diesen Wert in die sortierte Liste an der
richtigen Position einfügt (d.h., die Liste ist auch danach sortiert).
§ Vor addSorted(17) :
§ Nach addSorted(17) :
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
front = data next
-4
data next 17
data next 22
element 0 element 2 element 3
data next 8
element 1
Der “Normalfall”: irgendwo einfügen
§ Einfügen eines Elementes ”im Inneren” der Liste:
addSorted(17)
§ Welche Verweise (Referenzen) müssen geändert werden?
§ Was für eine Schleife bietet sich an?
§ Wann sollte die Schleife terminieren?
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
Erster Versuch
§ Fehlerhafte Schleife:
ListNode current = front;
while (current.data < value) { current = current.next;
}
§ Wo ist der Fehler?
§ Die Schleife endet zu spät um die Liste korrekt zu verändern.
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
current
Idee: vorausschauen
§ Korrekte Schleife:
ListNode current = front;
while (current.next.data < value) { current = current.next;
}
§ Diesmal hört die Schleife an der richtigen Stelle auf.
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
current
Spezialfall 1: Hinzufügen am Ende
§ Hinzufügen am Ende der Liste:
addSorted(42)
Exception in thread "main": java.lang.NullPointerException
§ Warum gibt es eine Exception?
§ Was können wir ändern um diesen Fall richtig zu behandeln?
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
Mehrere Tests für die Schleife
§ A correction to our loop:
ListNode current = front;
while (current.next != null &&
current.next.data < value) { current = current.next;
}
§ Wir müssen prüfen ob next den Wert null hat bevor wir das data Attribut des Knotens (d.h., next.value) prüfen
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
current
Spezialfall 2: Hinzufügen am Anfang
§ Einfügen am Anfang der Liste:
addSorted(-10)
§ Was passiert jetzt in unserem Programm?
§ Wie können wir diesen Fehler beheben?
front = data next
-4
data next 8
data next 22
element 0 element 1 element 2
Hinzufügen am Anfang
§ Eine weitere Verbesserung des Programms
if (value <= front.data) {
// insert at front of list
front = new ListNode(value, front);
} else {
// insert in middle of list ListNode current = front;
while (current.next != null &&
current.next.data < value) { current = current.next;
} }
§ Kann diese Methode jetzt alle möglichen Fälle behandeln?
Spezialfall 3: Leere Liste
§ Hinzufügen (am Anfang) zu einer leeren Liste:
addSorted(42)
§ Was passiert jetzt in unserem Programm?
§ Wie können wir diesen Fehler beheben?
front =
Endgültige Version
// Adds given value to list in sorted order.
// Precondition: Existing elements are sorted public void addSorted(int value) {
if (front == null || value <= front.data) { // insert at front of list
front = new ListNode(value, front);
} else {
// insert in middle of list ListNode current = front;
while (current.next != null &&
current.next.data < value) { current = current.next;
} }
}
(Verknüpfte) Liste vs. Array
§ Algorithmus um die Werte der Liste auszugeben:
ListNode front = ...;
ListNode current = front;
while (current != null) {
System.out.println(current.data);
current = current.next;
}
§ Algorithmus um die Werte des Arrays auszugeben:
int[] a = ...;
int i = 0;
while (i < a.length) {
System.out.println(a[i]);
i++;
}
Diskussion Liste vs. Array
§ Vorteil Array
§ Konstante Zugriffszeit
§ Vorteil Liste
§ Grösse flexibel
Ein paar Fragen
§ Was ist der Unterschied zwischen einer LinkedIntList und einem ListNode?
§ Was ist der Unterschied zwischen einer leeren und einer null Liste?
§ Wie können wir jede von ihnen konstruieren/generieren
Ein paar Fragen
§ Die Attribute von ListNode sind nicht private? Ist das guter oder schlechter Stil?
§ Welchen Effekt hat dieses Codesegment auf eine LinkedIntList values?
ListNode current = values.front;
current = null;
Antworten
§ Eine Liste besteht aus 0 oder mehr Knoten.
§ Jeder Knoten ist ein ListNode Objekt
§ Jeder Knoten enthält einen einzigen (int) Wert.
§ null Liste:
LinkedIntList list = null;leere Liste:
LinkedIntList list = new LinkedIntList();Antworten
§ Das kann man vertreten da LinkedIntList der einzige Klient von ListNode ist
§ Andere Programme manipulieren nicht die ListNode Objekte sondern arbeiten mit Methoden der LinkedIntList Klasse.
§ Es gibt in Java noch bessere Möglichkeiten, solche Klassen zu organisieren, aber die lernen wir erst später kennen.
§ Diese Zuweisungen ändern die Liste nicht. Die Liste kann nur auf folgende Weise verändert werden:
§ Aendern des front Attributes.
§ Aendern des next Verweises auf einen Knoten in der Liste
§ (Aendern des data Attributes eines Knotens)
Andere Operationen für Listen
§ Implementieren Sie weitere Methoden für LinkedIntList:
§ size
§ isEmpty
§ clear
§ toString
§ indexOf
§ contains
§ Deklarieren Sie ein size Attribut so dass die Anzahl Knoten schnell zurückgegeben werden kann.
252-0027
Einführung in die Programmierung 8.0 Vererbung
Thomas R. Gross
Department Informatik ETH Zürich
Copyright (c) Pearson 2013 and Thomas Gross 2016 All rights reserved.
Software Entwicklung
§ Programmieren ist anspruchsvoll
§ Es ist leicht Fehler zu machen
§ LinkedIntList Aufgaben
§ Wir würden gerne Software wiederverwenden
§ Auf früheren Lösungen aufbauen
§ Von LinkedIntList zu DoubleLinkedIntList
§ Von LinkedIntList zu LinkedBooleanList, LinkedPersonList, ….
56
Software Entwicklung
§ Programmieren ist anspruchsvoll
§ Es ist leicht Fehler zu machen
§ LinkedIntList Aufgaben
§ Wir würden gerne Software wiederverwenden
§ Auf früheren Lösungen aufbauen
§ Von LinkedIntList zu DoubleLinkedIntList
§ Von LinkedIntList zu LinkedBooleanList, LinkedPersonList, ….
58
Knoten einer doppelt verknüpften Liste
public class DllNode { int data;
DllNode next;
DllNode prev;
§ Jeder Knoten der Liste speichert:
}§ Den Wert einer ganzen (int) Zahl
§ Einen Verweis auf einen Vorgänger Listenknoten
§ Einen Verweis auf einen Nachfolger Listenknoten
prev data next 42
prev data next -3
prev data next 17
prev data next 9
Doppelt verknüpfte Liste
public class DoubleLinkedIntList { private DllNode front;
private DllNode tail;
// methods }
60 front
tail
DoubleLinkedIntList
DllNode DllNode DllNode
element 0 element 1 element 2
prev data next -3
prev data next 17
prev data next 9
Uebersicht
§ 8.0 Neue Klassen aus existierendem Klassen
§ 8.1 Konstruktoren
§ 8.2 Selektiv Verhalten (von Objekten) festlegen
61
Spital Beispiel
§ Gemeinsame Regeln für alle Angestellten: Arbeitszeit, Urlaub, Sozialleistungen, Fortbildung, Pflichtenheft, …
§ Alle Angestellten besuchen eine gemeinsame Orientierungveranstal- tung um die für alle gültigen Regeln des Krankenhauses zu erhalten
§ Verhalten im Notfall, professionelles Verhalten, Lohnfortzahlung im Krankheitsfall, …
§ Alle Angestellten erhalten das 20-seitige Handbuch, das die Arbeitsverhältnisse im Spital regelt
§ Aber …
§ Aber jede Abteilung hat noch ihre eigenen Regeln
§ Angestellte erhalten ein weiteres Handbuch (mit 1-5 Seiten) für die Regeln, die für ihre Abteilung gelten
63
§ Das Zusatzhandbuch enthält weitere Regeln und ändert oder erweitert Regeln aus dem (allgemeinen) Spitalregelwerk.
Angestellten Handbuch 20 Seiten
Arzt/Aerztin Handbuch
25 Seiten FaGe (Pflege) Handbuch
22 Seiten Adminstrator/in
Handbuch 21 Seiten
OP-Fachkraft Handbuch 25 Seiten
Organisation der Regeln
§ Warum wollen wir nicht je ein Handbuch für Aerzte/innen (25 Seiten), eines für FaGe (22 Seiten), eines für Administratoren (21 Seiten) und eines für OP-Fachkräfte (25 Seiten) haben?
§ Vorteile wenn wir die Handbücher aufteilen :
§ Anpassungen: Nur eine Stelle muss geändert werden, wenn sich die allgemeinen Regeln ändern.
§ Lokalitätsprinzip: Schneller Ueberblick über die Regeln die nur für Aerzte/innen gelten.
Was wir aus dem Beispiel mitnehmen
§ Allgemeine Regeln sind sinnvoll (das 20-seitige allgemeine Handbuch).
§ Einzelne Gruppen brauchen evtl. Zusatzregeln die nur für diese Abteilung gelten
§ Die Gruppenregeln haben Vorrang vor den allgemeinen Regeln
§ Die Gruppenregeln können evtl. allgemeine Regeln ausser Kraft setzen.
65
Regeln für Angestellte
§ Hier ist ein Satz von Regeln der für Angestellte des Krankenhauses gilt:
§ Die Arbeitszeit ist 42 Stunden pro Woche.
§ Angestellte erhalten einen Basislohn von 80’000 sFr/Jahr, bis auf OP-Fachkräfte die 10’000 sFr/Jahr extra erhalten, und Administratoren/-innen, die 5’000
sFr/Jahr extra erhalten.
§ Angestellte haben 4 Wochen Urlaub pro Jahr, bis auf Aerzte/innen, die eine Woche extra (also insgesamt 5 Wochen) bekommen
§ Um einen Urlaub zu beantragen sollten Angestellte ein grünes Formular verwenden, bis auf Aerzte/innen, die ein gelbes Formular brauchen.
68
Aufgaben und Fähigkeiten der Angestellten
§ Jede Art von Angestellten spielt im Spitalbetrieb eine bestimmte Rolle
§ Aerzte/innen behandeln Patienten (untersuchen und stellen eine Diagnose).
§ Administratoren verarbeiten Rechnungen.
§ FaGe pflegen Patienten auf einer Station (müssen also einer Station zugeteilt sein, für einen bestimmten Zeitraum)
§ OP-Fachkräfte managen den OP-Saal.
§ Wir wollen jetzt ein System erstellen, das die Spitaldirektion bei der Einsatzplanung, Rechnungsstellung etc unterstützt
§ Für jede/r Angestellte/n gibt es ein Exemplar einer Klasse mit der wir planen/verwalten können
69
Eine Klasse für Angestellte ( “ Angestellte ” )
// A class to represent employees in general (20-page manual).
public class Angestellte { public int getHours() {
return 42; // works 42 hours / week }
public double getSalary() {
return 80000.0; // sFr 80,000.00 / year }
public int getVacationDays() {
return 20; // 4 weeks paid vacation, not including weekends }
public String getVacationForm() {
return ”green"; // use the green form }
}