252-0027
Einführung in die Programmierung 11.0 Systematisches Programmieren
Thomas R. Gross
Department Informatik ETH Zürich
Copyright (c) Pearson 2013 and Thomas Gross 2016, 2019 All rights reserved.
Übersicht
§ 11.6 Entwurf von Klassen
2
Heuristik für Entwurf
1. Klassen identifizieren
2. Beziehung zwischen Klassen erarbeiten 3. Attribute
4. Methoden
Iterativ: mehrere Male durchspielen Entwurf verfeinern
3
4
5
Beispiel
6
Vereinfachungen
7
8
10
Fragen? Annahmen
§ Alle Fahrstühle sind unabhängig
§ Fahrstühle bewegen sich nur nach oben oder unten, d.h. die Kabinen bewegen sich nur vertikal, nicht horizontal, oder der Fahrstuhl steht auf einer Etage.
§ Zeit zum Öffnen/Schliessen der Türen kann vernachlässigt werden
11
12
From Wikimedia Commons under the creative commons cc-by-sa 3.0 license.
From YouTube video by ThyssenKrupp (accessed 12/20/19)
Klassen finden
§ Heuristik: Nomen im Text finden
13
18
19
Klassen finden
§ Heuristik: Nomen im Text finden und ordnen Fahrstuhl, Lift
Stockwerk, Etage, Einstiegsetage, Zieletage Simulator
Gebäude
Reisewunsch. Liftbewegung, Ruf Position, Richtung
20
Knöpfe, Ruf
Passagiere
§ Nicht jedes Nomen ist relevant
§ Knöpfe
§ Manche Nomen können wir nicht einordnen
§ Überblick, Zustand, Einsatz
§ Abgrenzung zwischen Nomen nicht immer klar
§ Ruf, Reisewunsch, Position
§ Position, Zieletage, Richtung
21
Erste Klassen Liste
§ Gebäude
§ besteht aus Etagen [Stockwerken] (Anzahl ist Parameter) und Fahrstühlen (Anzahl ist Parameter)
§ Passagier
§ generieren Reisewünsche (auf einer Ausgangsetage, zu einer Zieletage)
§ Fahrstuhl
§ bewegt sich nach oben bzw unten oder steht still
§ hat Position und Ziel
22
Fortsetzung
§ Simulator
§ für Gebäude mit N Stockwerken und M Fahrstühlen
§ 1-Sekunde Granularität
§ führt Buch
§ Logbuch
§ hält Ereignisse fest
23
24
25
Beziehung zwischen Klassen erarbeiten
§ Passagiere rufen Fahrstuhl
§ Fahrstuhl reist zur Ausgangsetage, öffnet sich, fährt zur Zieletage
§ Logbuch hält Ereignisse fest
26
verwendet
27
Gebaeude Simulator
Fahrstuhl Stockwerk
1..*
1 1
1
1..*
1
+main(args)
Beziehung zwischen Klassen erarbeiten
§ Passagiere rufen Fahrstuhl
§ Fahrstuhl reist zur Ausgangsetage, öffnet sich, fährt zur Zieletage
§ Logbuch hält Ereignisse fest
§ Etwas fehlt: wer entscheidet (wählt Fahrstuhl aus, findet nächste Ausgangsetage)?
§ Kontroller als Abstraktion der Fahrstuhlkontrolle
28verwendet
§ Rest der Beschreibung fügt noch mehr Elemente hinzu…
29
Gebaeude-Zentrale Simulator
Fahrstuhl Stockwerk
1..*
1 1
1
1..*
1
+main(args)
§ Brauchen wir Passagiere?
30
Attribute
§ Stockwerk:
§ Passagiere warten auf Reise nach oben
§ Passagiere warten auf Reise nach unten
§ Fahrstuhl
§ Position
§ Zieletage
§ Zustand: fahrend, wartend
31
Methoden
§ Simulator
§ einSchritt
§ verarbeiteWuensche
§ Stockwerk
§ resetWunsch(Richtung)
§ Fahrstuhl
§ setZiel
§ getPosition, getRichtung
§ moveCabin 32
u.s.w.
33
252-0027
Einführung in die Programmierung 12.0 Abstrakte Daten Typen
Thomas R. Gross
Department Informatik ETH Zürich
Copyright (c) Pearson 2013 and Thomas Gross 2016
All rights reserved. 35
Übersicht
12.1 Polymorphismus, noch einmal 12.2 Abstrakte Klassen
12.3 Java – was nicht im Manual steht equals, == und Boxing
12.4 Realität und Abstraktion
36
§ Polymorphismus ist wichtig.
37
38
§ Polymorphismus ist wichtig.
§ Eine Klasse soll eine minimale Schnittstelle definieren, die von allen anderen Klassen genutzt werden kann. (A.4)
39
LinkedList und ArrayList
§ Gleiches Verhalten (Menge von Methoden, Effekt der Methoden)
§ Unterschiedliche Implementation der List Collection
§ Kosten der Operationen sind (können) unterschiedlich (sein)
§ Speicherbedarf ist (kann) unterschiedlich (sein)
40
Methoden von ArrayList und LinkedList
add(value) appends value at end of list
add(index, value) inserts given value at given index, shifting subsequent values right
clear() removes all elements of the list
indexOf(value) returns first index where given value is found in list (-1 if not found)
get(index) returns the value at given index
remove(index) removes/returns value at given index, shifting subsequent values left
set(index, value) replaces value at given index with given value size() returns the number of elements in list
toString() returns a string representation of the list such as "[3, 42, -7, 15]"
add(value) appends value at end of list
add(index, value) inserts given value at given index, shifting subsequent values right
clear() removes all elements of the list
indexOf(value) returns first index where given value is found in list (-1 if not found)
get(index) returns the value at given index
remove(index) removes/returns value at given index, shifting subsequent values left
set(index, value) replaces value at given index with given value size() returns the number of elements in list
toString() returns a string representation of the list such as "[3, 42, -7, 15]"
§ Viele der Methoden sind vom List Interface vorgeschrieben
Abstrakte Daten Typen (ADT)
§ Abstrakter Daten Typ (ADT): Spezifikation einer Ansammlung von Daten und der Operationen, die mit diesen Daten
ausgeführt werden können.
§ Beschreibt was eine Ansammlung macht (oder mir ihr getan werden kann), nicht wie sie es macht
§ Wir wissen nicht wie ein XXXX implementiert ist, und wir brauchen dies auch nicht zu wissen.
§ Wir müssen nur das Konzept der Ansammlung verstehen, sowie die Operationen, die damit ausgeführt werden können.
Abstrakte Daten Typen (ADT)
§ In Java (insb. im Collection Framework) beschreiben wir ADTs mit Interfaces:
§ Collection, Deque, List, Map, Queue, Set, SortedMap
§ Ein ADT kann dann durch verschiedene Klassen realisiert sein:
§ ArrayList und LinkedList implementiert List
§ HashSet und TreeSet implementiert Set
§ LinkedList , ArrayDeque, etc. implementiert Queue
Arbeiten mit ADT Interfaces
§ Es ist eine gute Idee die Variablen für Ansammlungen als Variable des ADT Interface Typs zu deklarieren:
List<String> list = new ArrayList<String>();
§ Genauso sollten Methoden entsprechende Parameter mit ADT Interface Typen deklarieren:
public void stutter(List<String> list) { ...
}
Arbeiten mit ADT Interfaces
§ Es ist eine gute Idee die Variablen für Ansammlungen als Variable des ADT Interface Typs zu deklarieren:
List<String> list = new ArrayList<String>();
§ Genauso sollten Methoden entsprechende Parameter mit ADT Interface Typen deklarieren:
public void stutter(List<String> list) { ...
}
§ Flexibilität! Wir können diesen Code wiederverwenden
Warum sollten wir ADT verwenden?
§ Wer will mehr als eine Art von Listen, Warteschlangen, etc?
§ Jede Implementation kann für bestimmte Aufgaben effizienter sein
§ ArrayList ist schneller wenn wir Elemente am Ende einfügen/entfernen;
LinkedList ist schneller wenn wir Elemente in der Mitte einfügen/entfernen;
§ HashSet findet einen Wert in einer grossen Menge in kurzer Zeit;
TreeSet speichert die Werte sortiert.
52
Warum unterschiedliche Collections?
§ Manchmal brauchen wir eine Collection die weniger
anbietet (als z.B. ArrayList ) aber diese Operationen effizient durchführt.
§ Die Methoden des ADT müssen implementiert werden
§ Hier ist eine besondere Collection: Stack
§ Stack: Elemente werden in der umgekehrten Reihenfolge entfernt in der sie hinzugefügt wurden.
Stacks
§ Stack: Eine Ansammlung zu der Elemente hinzugefügt werden können und aus der Elemente entfernt
werden können.
§ Elemente werden in der umgekehrten Reihenfolge entfernt in der sie hinzugefügt wurden.
§ Last-In, First-Out ("LIFO")
§ Die Elemente werden in der Reihenfolge gespeichert in der sie hinzugefügt wurden, aber Elemente haben keine (fixe) Position
§ Also auch keinen Index
56
Stacks
§ Ein Klient kann nur Elemente hinzufügen/entfernen/das zuletzt hinzugefügte (d.h. oberste) Element inspizieren (der
"top” oder TOS [“top of stack”]).
§ Verhalten (Operationen):
§ push: Hinzufügen eines Elements (ist jetzt oberstes Element)
§ pop: Entfernen des obersten Elements
§ peek: Untersuchen/abfragen des obersten Elements.
57
Stacks in der Informatik
§ Compiler und Programmiersprachen:
§ Jeder Methoden Aufruf braucht Platz für die
lokalen Variablen – dieser wird auf einem Stack zur Verfügung gestellt (call=push, return=pop)
§ Compiler brauchen Stacks um einen
(arithmetischen oder logischen) Ausdruck zu evaluieren.
§ 7 + 5 * 6
method3 return varlocal varsparameters method2 return varlocal varsparameters method1 return varlocal varsparameters
59
§ Zuordnung von Symbolen:
§ Ist ein String ein Palindrome?
§ Prüfen Sie ob in einer Datei die Klammern { } ausgeglichen sind
§ Verwandeln Sie einen "infix" Ausdruck in einen "postfix" oder
"prefix” Ausdruck
§ Klevere Algorithmen:
§ Suchen Sie einen Pfad durch ein Labyrinth mit ”Backtracking"
§ Viele Programme unterhalten einen "undo stack” mit ausgeführten
Operationen 60
Die Klasse Stack
Stack<E>() constructs a new stack with elements of type E push(value) places given value on top of stack
pop() removes top value from stack and returns it;
throws EmptyStackException if stack is empty peek() returns top value from stack without removing it;
throws EmptyStackException if stack is empty size() returns number of elements in stack
isEmpty() returns true if stack has no elements
§ Beispiel
Stack<Integer> s = new Stack<Integer>();
s.push(42);
s.push(-3);
s.push(17); // bottom [42, -3, 17] top System.out.println(s.pop()); // 17
§ Stack unterstützt auch andere Methoden aber diese dürfen Sie (jetzt) nicht verwenden.
62
Stack Einschränkungen und Einsatz
§ Zur Erinnerung: Man kann nicht die Elemente mit einem for- Loop besuchen/inspizieren
Stack<Integer> s = new Stack<Integer>();
...
for (int i = 0; i < s.size(); i++) { do something with s.get(i);
}
§ Stattdessen muss man den Inhalt aus dem Stack nehmen um ihn zu untersuchen
§ Übliches Muster: Ein Element nach dem anderen wird entfernt bis der Stack leer ist.
Stack<Integer> s = new Stack<Integer>();
...
while (!s.isEmpty()) {
do something with s.pop();
}
64
Übung 1
§ Wir haben eine Ansammlung von Ergebnissen für Personen in (lexikographisch) umgekehrter Reihenfolge
Yeilding Janet 87 White Steven 84 Todd Kim 52 Tashev Sylvia 95
…
§ Schreiben Sie ein Programm das die Namen alphabetisch ausgibt (mit den Ergebnissen).
§ Was wenn wir die Daten nach der Ausgabe weiter bearbeiten wollen?
Übung 2
§ Wir haben einen Stack mit Integer Werten. Wir wollen die grösste Zahl finden.
66
Wo ist mein Stack?
§ Lösung: eine Method max , die einen Stack mit Integers als Parameter akzeptiert, und die grösste Zahl abliefert.
§ Diese Lösung sieht korrekt aus:
// s.size() > 0
public static int max(Stack<Integer> s) { int maxValue = s.pop();
while (!s.isEmpty()) { int next = s.pop();
maxValue = Math.max(maxValue, next);
}
return maxValue;
}
Wo ist mein Stack?
§ Das Programm zerstört den Stack um die Antwort zu finden.
§ Um dieses Problem zu umgehen muss man den Inhalt (des Stacks) speichern und nachher zurücksetzen:
// s.size() > 0
public static int max(Stack<Integer> s) {
Stack<Integer> backup = new Stack<Integer>();
int maxValue = s.pop();
backup.push(maxValue);
while (!s.isEmpty()) { int next = s.pop();
backup.push(next);
maxValue = Math.max(maxValue, next);
}
while (!backup.isEmpty()) { s.push(backup.pop());
}return maxValue;
}
69
70
Abstrakte Daten Typen (ADT)
§ In Java (insb. im Collection Framework) beschreiben wir ADTs mit Interfaces:
§ Collection, Deque, List, Map, Queue, Set, SortedMap
§ Ein ADT kann dann durch verschiedene Klassen implementiert sein:
§ ArrayList und LinkedList implementiert List
§ Stack implementiert ???
§ Ooops – Stacks wurden vergessen, es gibt nur eine Klasse (bzw List)
Abstraktion
§ Prozedural:
§ Details des Verhaltens (Prozeduren, z.B. der Methoden) nicht sichtbar
§ Spezifikation des Verhaltens ist die Abstraction
§ Müssen die Spezifikation mit einer Implementation erfüllen
§ Darstellung:
§ Details der Datendarstellung nicht sichtbar
§ Auch ein Weg Eigenschaften zu spezifizieren
§ Ein Ansatz über Programm + Daten zu folgern
§ Standard Terminologie: Abstrakte Data Typen, oder ADT
72
Warum ist Daten Abstraktion so wichtig
§ Arbeiten mit Daten zentrales Thema vieler Anwendungen
§ "Datenverarbeitung"
§ Data Science
§ Entwickeln (und Beschreiben) von Algorithmen seltener
§ Überlegen Sie sich welchen Datenstrukturen Sie brauchen
§ Wie werden die wichtigen Daten organisiert?
§ Welche Operationen dürfen Klienten mit den Daten machen?
73
Warum ist Daten Abstraktion so wichtig
§ Mögliche Probleme die sich beim Ausarbeiten der Abstraktion der Datendarstellung ergeben können:
§ Entscheidungen für/gegen eine Datenstruktur werden zu früh gemacht
§ Unnötige Wiederholungen (insbesondere wenn Transformationen gemacht werden)
§ Spätere Änderungen der (Kern) Datenstrukture(n) oft schwierig bzw aufwendig
§ Gliederung in Module hilft ist aber nicht einfach
74
Ein ADT definiert Operationen
§ ADT abstrahiert die Organization und betont die Bedeutung der Daten
§ ADT ändert Fokus von Struktur auf Gebrauch
§ Darstellung sollte für den Klienten nicht wichtig sein
§ Daher sollte sie nicht sichtbar sein!
§ Denken im Raum der Operationen
§ Erstellen eines Exemplars, getBase, getAngle, …. 75
class RightTriangle { double base, altitude;
}
class RightTriangle {
double base, hypot, angle;
}
Ein ADT definiert Operationen
§ ADT abstrahiert die Organization und betont die Bedeutung der Daten
§ ADT ändert Fokus von Struktur auf Gebrauch
§ Darstellung sollte für den Klienten nicht wichtig sein
§ Daher sollte sie nicht sichtbar sein!
§ Denken im Raum der Schnittstellen (d.h. interface)
§ Erstellen eines Exemplars, getBase, getAngle, …. 76
class RightTriangle { double base, altitude;
}
class RightTriangle {
double base, hypot, angle;
}
Vorteile eines Fokus auf ADTs
§ Wenn Klienten die Datenabstraktion respektieren (oder respektieren müssen)
§ z.B. arbeitet mit einem "Punkt in einer 2-dim Ebene mit diesen Operationen"
§ Entscheidung über die Implementation des ADT kann aufgeschoben werden
§ Können Fehler durch Änderung der Darstellung beheben
§ Algorithmen können geändert werden
§ Um (bessere) Leistung zu erhalten
§ Um besondere Situationen auszunutzen 79
Idee eines 2-d Punktes, als ein ADT
class Point {
// A 2-d point exists in the plane, ...
public double x() { … };
public double y() { … };
public double r() { … };
public double theta() { … };
// ... can be created, ...
public Point() { ... }; // new point at (0,0) public Point centroid(Set<Point> points) { … };
80
Observers
Creators/
Producers
Idee eines 2-d Punktes, als ein ADT (Teil 2)
// ... can be moved, ...
public void translate(double delta_x, double delta_y) { … };
public void scaleAndRotate(double delta_r,
double delta_theta) { … };
// attributes
private double x;
private double y;
} 81
Mutators
Point x y r theta translate scale_rot
Rest des Programms
"Abstraction barrier"
ADT = Objekte + Operationen
§ Implementation ist nicht sichtbar (versteckt)
§ Für Objekte des Typs gibt es nur die Operationen, die von der Abstraktion zugelassen sind
Klienten Implementation
82
Abstraktion und ADT
§ Zentrales Thema für die Entwicklung von Software Systemen
§ "Wenn Klienten die Datenabstraktion respektieren (oder respektieren müssen)"
83
Abstraktion und ADT
§ Zentrales Thema für die Entwicklung von Software Systemen
§ "Wenn Klienten die Datenabstraktion respektieren (oder respektieren müssen)"
84
Abstraktion und ADT
§ Zentrales Thema für die Entwicklung von Software Systemen
§ "Wenn Klienten die Datenabstraktion respektieren (oder respektieren müssen)"
§ Invarianten möglich
§ Programmiersprache stellt verschiedene Mittel zur
Verfügung den Klienten zu zwingen, die Datenabstraktion zu respektieren
§ Einschränkung der Sichtbarkeit durch Packages
85
Nested classes
§ Geschachtelte Klasse (“nested class”): Eine Klasse die innerhalb einer anderen Klasse definiert ist.
§ Können als static oder non-static (default) Klassen definiert werden
§ non-static nested classes heissen inner classes (innere Klasse)
86
Inner classes
§ Warum:
§ Innere Klassen sind nicht sichtbar für andere Klassen (Abkapselung)
§ Innere Objekte können die Attribute des äusseren Objekts lesen/modifizieren
§ Aber:
§ Exemplare der inneren Klasse existieren nur innerhalb eines Exemplars der sie umschliessenden (outer) Klasse
Exemplar der inneren Klasse
Exemplar der äusseren Klasse
87
Inner Class Syntax
// outer (enclosing) class public class outerName {
...
// inner class
private class innerName { ...
} }
88
Typ Parameter (Generics)
ArrayList< Type > name = new ArrayList< Type >();
§ Zur Erinnerung: Um eine ArrayList aus java.util zu konstruieren müssen wir den Typ der Elemente zwischen <
und > angeben
§ Wir sagten dass die ArrayList Klasse einen Typparameter erfordert
ArrayList<String> names = new ArrayList<String>();
names.add("Roman Bürki");
names.add("Urs Suter");
Generics und innere Klassen
public class Outer<T> {
private class Inner<T> {} // incorrect
private class Inner {
// koennen T verwenden
} // correct
}
§ Wenn die äussere Klasse einen Typparameter deklariert dann kann dieser Typparameter auch von den inneren Klassen verwendet werden.
§ Innere Klassen sollten nicht den Typparameter erneut deklarieren (dies würde einen 2. Typparameter deklarieren der den 1. verdeckt).
91
Aber: Typparameter unterliegen weiteren Einschränkungen
§ Es ist nicht erlaubt, Exemplare eines Parameter Typs mittels des new Operators zu erstellen. Das selbe gilt für Arrays eines Parameter
Typs.
Typparameter unterliegen weiteren Einschränkungen
public class Foo<T> {
private T myField; // ok public void method1(T param) { // ok
myField = new T(); // error T[] a = new T[10]; // error
Typparameter unterliegen weiteren Einschränkungen
§ Es ist nicht erlaubt, Exemplare eines Parameter Typs mittels des new Operators zu erstellen. Das selbe gilt für Arrays eines Parameter
Typs.
§ Es ist erlaubt, Variablen und Attribute eines solchen Typs zu
definieren, als Parameter oder Rückgabewert zu verwenden, oder Arrays durch einen Cast (Typumwandlung) von Object[] zu
erstellen.
Typparameter unterliegen weiteren Einschränkungen
public class Foo<T> {
private T myField; // ok public void method1(T param) {
myField = new T(); // error T[] a = new T[10]; // error
myField = param; // ok T[] a2 = (T[]) (new Object[10]); // ok }
}
96
§ Das ist aber nicht alles. Es gibt noch viele weitere Konzepte, die Sie in späteren Vorlesungen kennenlernen (sollten)
97
12.2 Abstrakte Klassen
98
LinkedList und ArrayList
§ Gleiches Verhalten (Menge von Methoden, Effekt der Methoden)
§ Unterschiedliche Implementation der List Collection
§ Kosten der Operationen sind (können) unterschiedlich (sein)
§ Speicherbedarf ist (kann) unterschiedlich (sein)
99
Methoden von ArrayList und LinkedList
add(value) appends value at end of list
add(index, value) inserts given value at given index, shifting subsequent values right
clear() removes all elements of the list
indexOf(value) returns first index where given value is found in list (-1 if not found)
get(index) returns the value at given index
remove(index) removes/returns value at given index, shifting subsequent values left
set(index, value) replaces value at given index with given value size() returns the number of elements in list
toString() returns a string representation of the list such as "[3, 42, -7, 15]"
§ Einige der Methoden können für beide Klassen (evtl) durch den selben Code implementiert werden (d.h. sind identisch für die Array-basierte als auch die Ketten-basierte Klasse)
§ add(value)
§ contains()
§ isEmpty()
Methoden von ArrayList und
LinkedList
public void add(int value) { add(size(), value);
}
public boolean contains(int value) { return indexOf(value) >= 0;
}
public boolean isEmpty() { return size() == 0;
}
102
§ Einige der Methoden können für beide Klassen (evtl) durch den selben Code implementiert werden (d.h. sind identisch für die Array-basierte als auch die Ketten-basierte Klasse)
§ add(value)
§ contains()
§ isEmpty()
§ Diese Methoden könnten im interface List implementiert werden
§ Muss aber dann eine Klasse sein
Methoden von ArrayList und
LinkedList
§ Sollten wir List in eine Klasse umwandeln?
Warum/Warum nicht?
§ Können wir auf andere Weise diese (häufige) Situation behandeln?
104
Abstrakte Klassen (“Abstract Classes”)
§ abstract class: Eine spezielle Klasse die eine Mischform zwischen Interface und Klasse ist.
§ Definiert einen Superclass-Typ mit Methodendeklarationen (wie ein Interface) und vollständigen Methoden (mit Rumpf/Body) (wie eine Klasse).
§ Definiert Attribute (wie eine Klasse) oder Konstanten (wie ein Interface)
§ Abstrakte Klassen können nicht instanziert werden (d.h. der new Operator kann nicht Exemplare dieses Typs generieren).
§ Klassen die nicht abstrakt sind (wie unsere bisherigen Klassen)
heissen konkrete (concrete) Klassen
§ Abstrakte Klassen können erweitert werden
§ Abgeleitete Klasse ist entweder auch abstrakt oder konkret (wenn es für alle Methoden eine Implementation gibt)
§ Was gehört in eine abstrakte Klasse?
§ Implementation gemeinsamen Zustandes (Attribute) oder
gemeinsamen Verhaltens, die von allen Subclasses geerbt werden soll (abstrakte Klassen sind Superclasses/Eltern in der Ableitungs- hierarchie)
§ Abstrakte Methoden die die Subclasses implementieren müssen
§ Schreiben Verhalten vor (Rolle eines Interfaces)
106
Abstract Class Syntax
// declaring an abstract class public abstract class name {
...
// declaring an abstract method
// (any subclass must implement it) public abstract type name(parameters);
}
Methoden Deklaration -- M. Definition
§ Deklaration (in abstrakter Klasse)
§ Mit Keyword abstract
§ Muss Parameter, Rückgabewert und Sichtbarkeit festlegen
§ Definition (in konkreter Unterklasse/Subclass)
§ Mit Rumpf
§ Kann in abgeleiteten Klassen überschrieben werden
108
§ Es ist erlaubt, Referenzvariable des abstrakten Typs zu deklarieren (aber nicht Objektexemplare zu generieren)
§ Wie bei Interfaces
§ Eine Erweiterung (mittels extends ) ist auch wieder
abstrakt (und muss als abstract deklariert sein) sofern nicht alle abstrakten Methoden implementiert sind.
§ Eine Klasse kann als abstract deklariert werden, auch wenn sie keine abstrakten Methoden enhält.
109
Abstract Classes vs. Interfaces
§ Normale Klassen die behaupten, ein Interface zu implementieren, müssen alle Methoden des Interfaces implementieren:
public class Empty implements IntList {} // error
§ Abstract classes können behaupten, ein Interface zu
implementieren ohne Code für die Methoden zu enthalten – eine Subclass muss die Methoden implementieren.
public abstract class Empty implements IntList {} // ok public class Child extends Empty {} // error
Abstrakte Klassen
§ Erlauben Wiederverwendung von (partiellen) Lösungen
§ Vielfach in der Implementation des Java Systems eingesetzt
111
Java Collection Framework
112
<<Interface>
Collection
<<Interface>
List <<Interface>
Set AbstractCollection
AbstractList AbstractSet
AbstractSequentialList
LinkedList
ArrayList TreeSet
<<Interface>
SortedSet
HashSet
<<Interface>
Map
AbstractMap
TreeMap
<<Interface>
SortedMap
HashMap
12.3 equals, == und Boxing
113
Für Referenztypen benutzen wir equals
§ Sie erinnern sich
114
Die equals Methode
§ String Objekte werden mit einer Methode mit Namen equals verglichen
.
Scanner console = new Scanner(System.in);
System.out.print("Wie heissen Sie? ");
String name = console.next();
if (name.equals(”Hase")) {
System.out.println("Wissen Sie mehr? ");
...
}
Vergleiche von String Objekten
§ Vergleichsoperatoren wie < und == funktionieren nicht wie vielleicht erwartet für Objekte.
Scanner console = new Scanner(System.in);
System.out.print(”Wie heissen Sie? ");
String name = console.next();
if (name == ”Hase") {
System.out.println(”Wissen Sie mehr? ");
} else {
System.out.println("Gehen Sie!");
}
§ Dieses Programm wird übersetzt aber der Test ergibt nie true .
Wie heissen Sie?
Gehen Sie!
Hase
Gilt für alle Referenztypen
Point p1 = new Point(4,5);
Point p2 = new Point(4,5);
if (p1==p2) { // always false!
}
if (p1.equals(p2)) { // true!
…
Wir müssen (evtl) Methode equals() aus Object
überschreiben
117Für alle Referenztypen
§ Der Vergleichsoperator == testet für Objektreferenzen ob es sich um das selbe Exemplar handelt
ListNode front, current;
...
if (front == current) { // circular list }
§ Kann auch (je nach Problem) sinnvoll sein
118
Das selbe Exemplar vs. gleiche Exemplar
§ Für Basistypen gibt es keinen Unterschied
int x = 5;
int y = x;
if (x==5) { … } if (x==y) { … }
§ Die Zahl "5" gibt es nur einmal
§ Und wir könnten equals() nicht verwenden da es kein Objektexemplar gibt
119
(Automatisches Un-)Boxing
§ … wurde zu Java hinzugefügt nachdem man Erfahrungen mit Wrapper Typen ( Integer , Double , …) hatte
§ Automatisches Boxing/Unboxing kann zu Überraschungen führen, denn die Java Laufzeitumgebung versucht, den
Speicherplatz sparsam zu benutzen
120
Arbeiten mit Wrapper Typen [Java 8]
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln für Referenzvariable
121
Integer i1 = new Integer(0);
Integer i2 = new Integer(0);
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output [Java 8] wie (?) erwartet
}Integer 0 and 0 : Not Equal
Arbeiten mit Wrapper Typen [Java 8]
122
Integer i1 = new Integer(128);
Integer i2 = new Integer(128);
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output [Java 8] wie (?) erwartet
}Integer 128 and 128 : Not Equal
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln für
Referenzvariable
Arbeiten mit Wrapper Typen [Java 10++]
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln für Referenzvariable
123
Integer i1 = new Integer(0);
Integer i2 = new Integer(0);
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output [Java 10++] wie (?) erwartet
}Integer 0 and 0 : Not Equal
javac -Xlint:deprecation BoxingS.java BoxingS.java:29: warning: [deprecation]
Integer(int) in Integer has been deprecated Integer i2 = new Integer(0);
Arbeiten mit Wrapper Typen [Java 10++]
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln für Referenzvariable
124
Integer i1 = Integer.valueOf(0);
Integer i2 = Integer.valueOf(0);
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output [Java 10++] wie (?) erwartet
}Integer 0 and 0 : Equal
Ohne deprecated Konstruktor
Arbeiten mit Wrapper Typen [Java 10++]
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln für Referenzvariable
125
Integer i1 = Integer.valueOf(128);
Integer i2 = Integer.valueOf(128);
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output [Java 10++] wie (?) erwartet
}Integer 128 and 128 : Not Equal Ohne deprecated Konstruktor
Boxing von Wrapper Typen [Java 8 & 10++]
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln manchmal nicht
126
Integer i1 = 0;
Integer i2 = 0;
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output wie erwartet
}Integer 0 and 0 : Equal
Boxing von Wrapper Typen
§ Für Exemplare eines Wrapper Typs gelten die üblichen Regeln manchmal doch
127
Integer i1 = 128;
Integer i2 = 128;
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output wie erwartet
}Integer 128 and 128 : Not Equal
Verwendung einer int Variable ändert nichts
Vorsicht bei automatischem (Un)Boxing
§ Ausdrücke mit Integer Exemplaren, die durch Boxing entstanden, können zu Überraschungen führen
128
ArrayList<Integer> list = new ArrayList<Integer>();
int n = 420;
list.add(n);
list.add(n);
if (list.get(0) == list.get(1)) { System.out.println("Equal");
} else {
System.out.println("Not Equal");
}
int n = 42;
list.add(n);
list.add(n);
if (list.get(0) == list.get(1)) { System.out.println("Equal");
} else {
System.out.println("Not Equal");
}
Vorsicht bei automatischem (Un)Boxing
§ Ausdrücke mit Integer Exemplaren, die durch Boxing entstanden, können zu Überraschungen führen
129
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(420));
list.add(new Integer(420));
if (list.get(0) == 420) {
System.out.println("Equal");
} else {
System.out.println("Not Equal");
}
list.add(new Integer(42));
list.add(new Integer(42));
if (list.get(0) == 42) {
System.out.println("Equal");
} else {
System.out.println("Not Equal");
}
Vorsicht bei Wrapper Typen
§ Auch Integer.valueOf(int value) schützt nicht immer vor Überraschungen
§ Siehe vorherige Beispiele
130
§ Für manche Werte wird beim Boxing das Integer Exemplar
wiederverwendet (hier für 42) und bei anderen nicht (für 420).
§ "Ideally, boxing a primitive value would always yield an identical reference. In practice, this may not be feasible using existing
implementation techniques. [..] [C]ertain common values [should]
always be boxed into indistinguishable objects." Oracle Java Doc (jls-5.1.7)
§ "Common values" wird vom Compiler/Laufzeitsystem definiert, d.h. ist "implementation dependent"
§ Unterschiedliche Systeme haben evtl. unterschiedliche Werte
§ Das System kann konfiguriert werden
java -Djava.lang.Integer.IntegerCache.high=420 Boxing
§ d.h. an unterschiedlichen Tagen kann es ein anderes Verständnis von
"common values" geben.
131
java -Djava.lang.Integer.IntegerCache.high=130
§ Damit stellen wir sicher dass
Integer i1 = Integer.valueOf(128);
Integer i2 = Integer.valueOf(128);
§ auf das selbe Exemplar verweisen
System.out.print("Integer "+ i1+" and "+i2+" :");
if (i1 == i2){
System.out.println(" Equal");
} else {
System.out.println(" Not Equal");
§ Output [Java 10++] wie (?) erwartet
}Integer 128 and 128 : Equal
132
Mein Ratschlag
§ Für Objektexemplare benutzen wir equals()– auch für Wrapper Typen
133
ArrayList<Integer> list = new ArrayList<Integer>();
int n = 420;
list.add(n);
list.add(n);
if ( (list.get(0)).equals(list.get(1)) ) { System.out.println("Equal");
} else {
System.out.println("Not Equal");
}
It is easier to write an incorrect program than understand a correct one.
Alan Perlis
1922-1990
1st Department Head at Carnegie Mellon 1st Winner of the Turing Award
134
12.4 Realität und Abstraktion
§ Endliche Darstellung von Zahlen
135
Realität und Abstraktion
§ Gegeben
int i;
Gilt i*i >= 0 ?
136
Realität und Abstraktion
§ Gegeben
int i;
Gilt i*i >= 0 ?
public class Weird {
public static void main (String[] args) { int i = 40000;
int j = 50000;
System.out.println(i*i);
System.out.println(j*j);
} }
137
Realität und Abstraktion
§ Gegeben
int i;
Gilt i*i >= 0 ?
public class Weird {
public static void main (String[] args) { int i = 40000;
int j = 50000;
System.out.println(i*i); // 1600000000 System.out.println(j*j); // -1794967296 } }
138
Endliche Darstellung(en)
§ Eine int Variable wird durch 32 Bits dargestellt
§ Allgemein: X hat w Bits xw-1 xw-2 .. x1 x0
§ Wir hatten (vielleicht) früher schon gesehen wie für X diese Abbildung Bit ➜ Integer (Integer(X)) realisiert ist:
139
Integer ( X ) = x
i⋅ 2
ii=0 w−1
∑
Endliche Darstellung
§ Mit dieser Abbildung können wir mit w Bits Zahlen in Bereich von 0 … 2
w– 1 darstellen
§ Zahlen ohne Vorzeichen ("unsigned")
§ Seit Java 8 auch in Java ...
§ Die Abbildung nennen wir daher B2U (Binary-to-Unsigned)
140
B2U ( X ) = x
i⋅ 2
ii=0 w−1
∑
Negative Zahlen
§ Wenn wir w Bits zur Verfügung haben dann ist eine praktische Darstellung das Zweierkomplement (Two's Complement)
§ B2T – Binary-to-Two's complement
§ Bit w-1 ist das Vorzeichenbit (daher auch "signed")
§ 0: Zahl positiv
§ 1: Zahl negativ
141
B2T ( X ) = − x
w−1⋅ 2
w−1+ x
i⋅ 2
ii=0 w−2
∑
Positive & negative Zahlen
§ Um uns ein Bild zu verschaffen arbeiten wir mit w == 4
§ Unsigned Bereich: 0 … 15
§ Signed Bereich: -8 ... 7
§ (– 2w-1) … (2w-1 – 1)
§ Addition/Subtraktion können effizient implementiert werden
§ Identische Hardware für signed und unsigned
142
X B2U(X) B2T(X)
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
–8 8
–7 9
–6 10
–5 11
–4 12
–3 13
–2 14
–1 15
1000 1001 1010 1011 1100 1101 1110 1111
0 1 2 3 4 5 6 7
Positive & negative Zahlen
§ Beispiel Addition: 2 + 4
2: 0010 4: 0100 -7:0110
143
Positive & negative Zahlen
§ Beispiel Addition: 2 + 4
2: 0010 4: 0100 6: 0110
144
Positive & negative Zahlen
§ Beispiel Addition: –2 + 4
–2: 1110 4: 0100 2:0010
145
Positive & negative Zahlen
§ Beispiel Addition: –2 + 4
–2: 1110 4: 0100 2:0010
§ Was passiert wenn unser Ergebnis nicht dargestellt werden kann:
§ Wrap-around
146
Positive & negative Zahlen
§ Beispiel Addition: 5 + 4
5: 0101 4: 0100 6: 1001
147
Positive & negative Zahlen
§ Beispiel Addition: 5 + 4
5: 0101 4: 0100 6: 1001
148
Wäre 9 wenn wir kein
Vorzeichen hätten (also mit unsigned Zahlen arbeiteten)
Positive & negative Zahlen
§ Beispiel Addition: 5 + 4
5: 0101 4: 0100 -7: 1001
149
Wäre 9 wenn wir kein
Vorzeichen hätten (also mit unsigned Zahlen arbeiteten)
Aber wir arbeiten mit
Zahlen mit Vorzeichen
(signed)
§ Daher gilt (für 4-Bit Addition): 7 + 1 == – 8
int bigInt = Integer.MAX_VALUE;
System.out.println(bigInt);
System.out.println(bigInt+1);
150
§ Daher gilt (für 4-Bit Addition): 7 + 1 == – 8
int bigInt = Integer.MAX_VALUE;
System.out.println(bigInt); // 2147483647 System.out.println(bigInt+1); // -2147483648
§ aber …. (Java 8!)
String sInt = Integer.toUnsignedString(bigInt+1);
System.out.println(sInt); // 2147483648
151
Warum ist das wichtig?
§ Für int gilt (leider) nicht
§ intA > intB ⇒ (intA+1) > (intB+1)
§ Müssen sicherstellen dass unser Programm nur Werte im Bereich von (– 2
w-1) … (2
w-1– 1) produziert.
152
Das ist aber nicht alles …
§ Gilt denn wenigstens
(a + b) + c == a + (b + c)?
§ Für int ja.
153
Realität und Abstraktion
§ Gegeben
double d, e, f;
Gilt (d + e) + f == d + (e + f) ?
public class Weird {
public static void main (String[] args) { double d = 1e308;
System.out.println( (d + -d) + 3.14);
System.out.println(d + (-d + 3.14));
} } 154
Realität und Abstraktion
§ Gegeben
double d, e, f;
Gilt (d + e) + f == d + (e + f) ?
public class Weird {
public static void main (String[] args) { double d = 1e308;
System.out.println( (d + -d) + 3.14); // 3.14 System.out.println(d + (-d + 3.14)); // 0.0
} } 155
Das ist aber nicht alles …
§ Gilt denn wenigstens
(a + b) + c == a + (b + c)?
§ Für int/long ja.
§ Für float/double nein.
156
Vorsicht
§ wenn Ihr Programm rechnet
§ Mehr Bits ( long , double vs float ) helfen nur begrenzt
157
159
“There’s no sense in being precise when you don’t even know what you’re talking about.”
J. von Neumann