252-‐0027
Einführung in die Programmierung I 6.0 Objekte
Thomas R. Gross
Department Informa@k ETH Zürich
Copyright (c) Pearson 2013. and Thomas Gross 2016 All rights reserved.
Zugriff auf A+ribute
Andere Klassen können auf die A+ribute eines Objektes zugreifen (lesen oder verändern)
Zugriff (Lesen): variable.field
Verändern: variable.field = value;
Beispiel:
Point p1 = new Point();
Point p2 = new Point();
System.out.println("the x-coord is " + p1.x); // access p2.y = 130; // modify
Arbeiten mit Objekten
Konkretes Objekt erstellt nach Vorlage in Klasse
ObjekFnstanz, Instanz ("instance")
Exemplar der Klasse
Zugriff auf A+ribute nur möglich wenn es Instanz gibt
Klasse ist die Vorlage
Daher können in der Klasse keine Anweisungen sein (ausser für Initalisierung und in Methoden)
Operator new
Referenz auf konkretes Objekt
43
Arbeiten mit Objekten
Konkretes Objekt erstellt mit dem Operator new
new class()
Liefert eine Reference (Verweis) auf neues Objekt
Klienten sind alle die Programme die Instanzen einer Klasse erstellen oder auf Instanzen zugreifen (können) [z.B. weil sie als Parameter übergeben wurden]
Klient: Beziehung zwischen Klassen
Programm: muss in einer Klasse sein 44
Arbeiten mit Objekten
new liefert Verweis auf Instanz
Kann in einer Variable gespeichert werden Point p = new Point();
Wir sagen dass p eine Referenzvariable ("reference variable") ist.
Besser: p ist eine Variable eines Referenztyps
Im Gegensatz zu Variablen eines Basistypes (eingebauten Typs)
Zugriff auf Objekte via Reference Variables
"Dot NotaFon”
int z = p.x; // p refers to a Point, see above
45
Reference SemanFcs
Für Reference Variables gelten die Reference SemanFcs Regeln
Point p1 = new Point();
p1.x = 3;
p1.y = 2;
Point p2 = p1; // p2.x == 3, p2.y == 2 p2.x = 4; // p2.x == 4, p2.y == 2 // p1.x == 4, p2.y == 2
46
47
Klassen und Klienten
Point.java ist (alleine) kein ausführbares Programm
Eine Klasse kann von Klienten verwendet werden.
PointMain.java (Klient)
public class PointMain { main(String args) {
Point p1 = new Point();
p1.x = 7;
p1.y = 2;
Point p2 = new Point();
p2.x = 4;
p2.y = 3;
...
} }
Point.java (Klasse für Objekte) public class Point { int x;
int y;
}
x 7 y 2
x 4 y 3
PointMain Beispiel für Klient
public class PointMain {
public static void main(String[] args) { // create two Point objects
Point p1 = new Point();
p1.y = 2;
Point p2 = new Point();
p2.x = 4;
System.out.println(p1.x + ", " + p1.y); // 0, 2 // move p2 and then print it
p2.x += 2;
p2.y++;
System.out.println(p2.x + ", " + p2.y); // 6, 1 }
}
Reference SemanFcs
Wir brauchen einen Weg, eine Reference Variable zurückzusetzen (zu nullifizieren)
Besonderer Wert null (gut für alle Klassen)
Point p1 = new Point();
p1.x = 3;
p1.y = 2;
Point p2 = p1; // p2.x == 3, p2.y == 2 p2.x = 4; // p2.x == 4, p2.y == 2 // p1.x == 4, p2.y == 2
p2 = null; // only p1 refers to Point (4,2) 50
Arrays mit Objekten
null : Ein Wert der auf kein Objekt verweist
Die Elemente eines Arrays für Objekte werden mit null iniFalisiert.
String[] words = new String[5];
DrawingPanel[] windows = new DrawingPanel[3];
index 0 1 2 3 4
value null null null null null
index 0 1 2
value null null null
words windows
Wofür null gut ist
Speichern von null in einer Variablen oder einem Array Element
String s = null;
words[2] = null;
Drucken des null Verweises (Referenz)
System.out.println(s); // null
Prüfen ob eine Variable oder Array Element null ist
if (words[2] == null) { ...
Wofür null gut ist
Uebergeben von null als ein Parameter einer Methode
System.out.println(null); // null
Zurückgeben von null von einer Methode (wird oe verwendet um einen Fehler anzuzeigen)
return null;
null Reference
null ist ein Wert (den eine Variable haben kann)
Variable mit Reference SemanFcs int [] a = new int[10];
a = null; // forget this array!
Hat eine Variable den Wert null so sprechen wir manchmal von einer "null reference"
54
Null Reference ExcepFon
Dereferenzieren ("dereference"): Zugriff auf A+ribute oder Methoden eines Objektes in Dot NotaFon, z.B. s.length().
Es ist nicht erlaubt, null zu dereferenzieren (Laufzeigehler, hat eine ExcepFon zur Folge).
Point p1 = new Point();
p1.x = 3; p1.y = 2;
Point p2 = p1; // p2.x == 3, p2.y == 2 p2 = null;
System.out.println(“p2.x :” + p2.x);
null ist nicht irgendein Objekt, d.h. es gibt keine Methoden oder Daten
Null Dereference ExcepFon
String[] words = new String[5];
System.out.println("word is: " + words[0]);
words[0] = words[0].toUpperCase(); // ERROR
Output:
word is: null
Exception in thread "main"
java.lang.NullPointerException
at Example.main(Example.java:8)
Der Name java.lang.NullPointerException verrät etwas über die ImplemenFerung von References
index 0 1 2 3 4
value null null null null null
luege, lose, laufe …
Sie können prüfen ob eine Referenz null ist bevor eine Methode für ein Objekt aufgerufen wird.
String[] words = new String[5];
words[0] = "hello";
words[2] = "goodbye"; // words[1], [3], [4] are null for (int i = 0; i < words.length; i++) {
if (words[i] != null) {
words[i] = words[i].toUpperCase();
}
} index 0 1 2 3 4
value "HELLO" null "GOODBYE" null null
words
IniFalisierung von Arrays
1) IniFalisierung des Arrays (jedes Element wird auf null gesetzt bei Objekten, 0 bei int etc)
2) IniFalsierung der Elemente
String[] words = new String[4]; // phase 1 for (int i = 0; i < words.length; i++) {
coords[i] = "word" + i; // phase 2 }
IniFalisierung in zwei Schri+en (Phasen)
index 0 1 2 3
value "word0" "word1" "word2" "word3"
words
A"ribute
A"ribute können können einen beliebigen Typ haben
Basis Typen
Strings
Arrays
…
Was wir A"ribut nennen heisst bei manchen Autoren Objekta"ribut.
2
Beispiel HoursWorked
Sinnvoll wäre hier ein Typ Person
public class Person { String name;
int id;
double [] hours;
}
Unser Programm (main) arbeitet dann mit einem Array von Person Objekten
Scanner input = new Scanner(new File("data.txt"));
Person [] staff = new Person[input.nextInt()];
for (int i=0; i < staff.length; i ++) { staff[i] = readData(input);
} 3
Uebersicht
6.2 Methoden
Copyright (c) Pearson 2013. and Thomas Gross 2016
All rights reserved. 4
Methoden beschreiben das Verhalten
Beschreiben das Verhalten eines Objektes
Verhalten – Zustandsänderungen oder Abfragen des Zustandes
Redundanz im Klienten
Unser Klientenprogramm möchte den Lohn für alle Angestellten berechnen
Gegeben ein Array von Person Objekten:
// compute salary
for (int i = 0; i < staff.length; i ++) { double sum = 0;
for (int j = 0; j < staff[j].hours.length; j++) { sum += staff[j].hours[j];
};
double salary = sum * 20.00 }; // for i
Redundanz im Klienten
Wenn wir diese Berechnung an mehreren Stellen durchführen wollen, müssen wir den Code kopieren …
Diese Art von Redundanz kann mit einer Methode verhindert werden
Methode computePay(Person p)
public static double computePay(Person p) { double sum = 0;
for (int k = 0; k < p.hours.length; k++) { sum += p.hours[k];
}
return sum * 20;
}
Ohne Redundanz, Version 1
main würde dann diese Methode aufrufen
// compute wages to be paid double totalWages = 0.0;
for (int i = 0; i < staff.length; i ++) { totalWages += computePay(staff[i]);
}
Probleme mit dieser Programmstruktur
Methode computePay(…) ist Teil von HoursWorked (dem Klienten)
Jedes Programm das mit Person Objekten arbeitet müsste eine computePay(…) Methode implemen^eren.
Objekte erlauben Wiederverwendung von Code – aber diese findet nicht sta" wenn jeder Klient den Code für die
Gehaltsberechnung duplizieren muss.
Probleme mit dieser Programmstruktur
Die Methode computePay(…) muss viele Einzelheiten über die Implementa)on von Person Objekten wissen
for (int k = 0; k < p.hours.length; k++) sum += p.hours[k];
}
Die A"ribute von Person können sich aber ändern
Eine mögliche Aenderung
Der Array hours enthält die Anzahl Stunden, die eine Person an einem Tag gearbeitet hat.
Was wenn wir zwischen Normalzeit und Ueberstunden unterscheiden wollen ?
Ersten 8 Stunden/Tag sind Normalzeit, sFr 20.00 pro Stunde
Ueber 8 Stunden gilt als Ueberstunde, 25% Zuschlag
Wir müssen Person Objekte anpassen und die Methoden computePay(…) in allen Klienten anpassen
11
Person mit Ueberstunden A"ribute
public class Person { String name;
int id;
double [] hours;
double [] overtime;
}
Viele andere A"ribute für rich^ge Personendaten …
12
computePay mit Ueberstunden
public static double computePay(Person p) { double sumStd = 0.0;
double sumOvt = 0.0;
for (int i = 0; i < p.hours.length; i++) { sumStd += p.hours[i];
}
for (int i = 0; i < p.overtime.length; i++) { sumOvt += p.overtime[i];
}
return sumStd * 20 + sumOvt*25;
} 13
Probleme mit dieser Programmstruktur
Wir wollen Klassen entwickeln die (innerhalb eines
bes^mmten Rahmens) von den Klienten unabhängig (weiter) entwickelt werden können.
Wir wollen Klienten entwickeln die von der Implementa^on der Klassen (die sie verwenden) unabhängig sind.
Probleme mit dieser Programmstruktur
Im Klienten ist überhaupt nicht ersichtlich dass computePay (…) eine Methode für Person Objekte ist
Es wird ein Person Objekt als Parameter übergeben
for (int i = 0; i < staff.length; i ++) { totalWages += computePay(staff[i]);
}
Person Objekte sind Parameter, aber kein weiterer Bezug zur Person Klasse
Probleme mit dieser Programmstruktur
Klassen sollten Zustand und Verhalten kombinieren.
Berechnung des Gehaltes computePay ist ein Verhalten das eng mit den Daten eines Person Objektes verbunden ist.
Diese Methode gehört daher in jedes Person Objekt.
Dann kann diese Methode in Dot Nota^on aufgerufen werden totalWages += staff[i].computePay();
Instanzmethoden
Instanzmethode ("instance method" oder auch "object
method"): Exis^ert innerhalb jedes Objekt(examplars) einer Klasse und beschreibt das Verhalten eines Objektes.
Syntax:
public type name(parameters) { statements;
}
Selbe Syntax wie bei den bisher bekannten Methoden aber ohne das Keyword static
Beispiele
public class SomeClass {
public void hello(String name) {
System.out.println("HELLO " + name);
} }
public class Person { // attributes omitted public void present() {
System.out.println(”In use”);
} }
// usage example on next slide
18
Beispiel, Fortsetzung
public class HoursWorked {
public static void main(String[] args) {
Scanner input = new Scanner(new File("data.txt"));
Person [] staff = new Person[input.nextInt()];
for (int i=0; i < staff.length; i ++) { staff[i] = readData(input);
}
// various updates, persons are hired/leave // check if entries are still in use
for (int i=0; i < staff.length; i ++) { staff[i].present();
} }
} 19
Instanzmethoden
public class Person { String name;
int id;
double [] hours;
double [] overtime;
// Computes wages, 25% overtime supplement public double computePay() {
… }
}
Die computePay Method hat nicht mehr einen Person p Parameter.
Wie "weiss" die Methode wieviele Std. eine Person gearbeitet hat?
Wie erhält die Methode Zugang zu Daten in hours und overtime?
Jedes Person Objekt hat seine eigene Kopie der computePay Methode, die mit dem Zustand dieses Objektes arbeitet:
Person p1 = new Person();
// read data
Point p2 = new Person();
// read data
p1.computePay();
p2.computePay();
Person Objekte mit Methoden
23
Person Objekte mit Methode computePay
public class Person { String name;
int id;
double [] hours;
double [] overtime;
// Computes wages, 25% overtime supplement public double computePay() {
double sumStd = 0;
double sumOvt = 0;
for (int i=0; i<hours.length; i++) { sumStd += hours[i];
}
for (int i=0; i<overtime.length; i++) { sumOvt += overtime[i];
}
return sumStd * 20 + sumOvt*25;
}
} 24
Der implizite Parameter
Impliziter ("implicit") Parameter: Das Objekt für das die Methode aufgerufen wird.
Während der Ausführung von p1.computePay();
ist der implizite Parameter das Objekt auf das p1 verweist.
Während der Ausführung von p2.computePay();
ist der implizite Parameter das Objekt auf das p2 verweist.
Die Instanzmethoden können mit den A"ributen dieses Objekts arbeiten (d.h. lesen und schreiben).
Die Instanzmethode wird im Kontext eines konkreten Objektes ausgeführt.
computePay kann auf hours und overtime des Objektes zugreifen für das diese Methode aufgerufen wurde.
Mehr A"ribute für Person
public class Person { String name;
int id;
double hourlyRate;
double [] hours;
double [] overtime;
// various methods …
}
Wenn wir für jede Person den Stundenlohn festhalten wollen
26
Zugriff auf A"ribute
Jeder Klient kann (bisher) auf alle A"ribute eines Objektes zugreifen (lesen und/oder modifizieren)
Dies ist nicht immer gewünscht
Sonst könnte jeder hourlyRate verändern …
Als Vorbereitung für eine bessere Struktur betrachten wir zwei Arten von Methoden:
27
Methoden
Accessor Methode ("accessor"): Eine Methode die es erlaubt den Zustand eines Objektes anzusehen
Beispiel: getAdresse(), getHourlyRate()
Hat sehr on einen Rückgabewert der nicht void ist (non-‐void return)
Mutator Methode ("mutator"): Eine Methode die den Zustand eines Objekts verändert
Beispiele: setHourlyRate(…), addTrainingTime(…),
setAdresse(…)
Mutator Methoden
Schreiben Sie eine Methode setHourlyRate die den Stundenlohn auf den übergebenen Betrag newRate setzt.
Schreiben Sie eine Methode addTrainingTime die für jeden gearbeiteten Tag die Normalarbeitszeit um
extraTime erhöht.
Mutator Methoden
public void setHourlyRate(double amount) { hourlyRate = amount;
}
public void addTrainingTime(double extra) { for (int i=0; i<hours.length; i++ ) {
hours[i] += extra;
}
Ausgabe (Drucken) von Objekten
Ohne weitere Hilfe weiss das Java System nicht, wie ein Objekt gedruckt werden soll:
Person[] staff = new Person[size];
// read from file
for (int i = 0; i < size; i++) {
System.out.println("MA " + i + " ist " + staff[i]);
}
Ausgabe:
MA 0 ist Person@c17164 MA 1 ist Person@1fb8ee3 MA 2 ist Person@61de33
Ausgabe (Drucken) von Objekten
Ohne weitere Hilfe weiss das Java System nicht, wie ein Objekt gedruckt werden soll:
Person[] staff = new Person[size];
// better, but cumbersome;
for (int i = 0; i < size; i++) {
System.out.println(”MA " + i + " ist " +
staff[i].name + " (#" + staff[i].id + ") " +
Arrays.staff[i].hours + " " + Arrays.staff[i].overtime);
}
Ausgabe:
MA 0 ist Paula (#123) [8.0, 8.0, 7.6, 3.2] [4.5, 0.09998, 0.0, 0.0]
37
Die toString Methode
Sagt dem Java System wie ein Objekt in einen String verwandelt wird
for (int i = 0; i < size; i++) {
System.out.println("MA " + i + " ist " + staff[i]);
}
// the above code is really calling the following:
System.out.println("MA " + i + " ist " +
staff[i].toString());
Es gibt für jede Klasse eine toString Methode selbst wenn sie nicht in Ihrer Klasse erscheint.
Die toString Methode
Die default toString Methode ist
KlassenName @ Adresse_im_Speicher
Nicht das was wir wollen …. aber wir können uns eine eigene schaffen
Bessere toString Methode
public String toString() {
code that returns a String represen>ng this object;
}
Name der Methode, Keyword public, return Typ String , und (kein) Parameter müssen genau s^mmen 39
toString Beispiel
// Returns a String representing this Person.
public String toString() {
return name + " (#" + id + ") ist " + Arrays.toString(hours) + " " + Arrays.toString(overtime);
}
Konstruk^on und Ini^alisierung von Objekten
Der new Operator liefert eine Referenz (einen Verweis) auf ein neues Objekt
new class(): Exemplar (Instanz) der Klasse class
new class[size]: Array der Länge size für Referenzen auf Exemplare der Klasse class
Vergleiche mit:
new int[size]: Array der Länge size für int Werte
Ini^alisierung von Objekten
Bisher waren mehrere Anweisungen nö^g, um ein Exemplar einer Klasse zu konstruieren und es zu ini^alisieren:
Point p = new Point();
p.x = 3;
p.y = 8;
(N+1) Anweisungen bei N A"ributen
Lange Folgen von Anweisungen
Leicht etwas zu übersehen
Ini^alisierung von Objekten
Besser wäre es die Werte für die A"ribute gleich anzugeben:
Point p = new Point(3, 8); // better!
Person employee = new Person(Paula, 123);
Wir können so etwas für viele Arten von Objekten in Java machen.
Konstruktoren
Konstruktor (“constructor”): Ini^alisiert den Zustand eines neuen Objektes.
public type(parameters) { statements;
}
Ausgeführt wenn der new Operator ausgeführt wird
Es gibt keinen Rückgabewert.
Im Rumpf können beliebige Anweisungen aunreten (wie in Methode)
Konstruktoren
Ein Konstruktor ist keine Methode
Konstruktoren sind op^onal
Wenn eine Klassendefini^on keinen Konstruktor enthält, dann stellt Java einen (voreingestellten) default Konstruktor (“default
constructor”) zur Verfügung
Der default Konstruktor hat keine Parameter und setzt alle Felder auf Null (entweder 0, 0.0, oder null)
Beispiele von Konstruktoren
public class Point { int x;
int y;
// Constructs a Point at the given x/y location.
public Point(int initialX, int initialY) { x = initialX;
y = initialY;
}
// Methods ...
}
Beispiele von Konstruktoren
public class Person { String name;
int id;
double hourlyRate;
double [] hours;
double [] overtime;
// Constructs a Person with given name and Id public Person(String firstname, int uniqueId) { name = firstname;
id = uniqueId;
}
// Methods ...
}
Ausführung eines Konstruktors in Zeitlupe
Was passiert wenn dieser Code ausgeführt wird?
Point p1 = new Point(7, 2);
Ausführung eines Konstruktors in Zeitlupe
Was passiert wenn dieser Code ausgeführt wird?
Point p1 = new Point(7, 2);
public Point(int initialX, int initialY) { x = initialX;
y = initialY;
}
public void setLocation(int newX, int newY) {
…
x y
p1
Ausführung eines Konstruktors in Zeitlupe
Was passiert wenn dieser Code ausgeführt wird?
Point p1 = new Point(7, 2);
public Point(int initialX, int initialY) { x = initialX;
y = initialY;
}
public void setLocation(int newX, int newY) {
…
x y
p1
52
Mehrere Konstruktoren
Eine Klasse kann mehrere Konstruktoren haben.
Jeder Konstruktor muss eine unverwechselbare Liste von Parametern haben
Entscheidend ist dass die Typen der Parameterliste unverwechselbar sind
Erlaubt
public Point(int initialX, int initialY) { x=initialX; y=initialY; } public Point(int initialX) {x = nitialX; y = 0;}
Nicht erlaubt
public Point(int initialX, int initialY) { x=initialX; y=initialY; } public Point(int a, int b) { x = a; y = b; }
Schreiben Sie einen Point Konstructor ohne Parameter der den Punkt mit (0, 0) ini^alisiert.
// Constructs a new point at (0, 0).
public Point() { x = 0;
y = 0;
}
56
Häufige Fehler in Konstruktoren
1. (Erneute) Deklara^on von A"ributen als Variable:
public Point(int initialX, int initialY) { int x = initialX;
int y = initialY;
}
Jetzt gibt es Variable x und y die nur im Konstruktor bekannt sind.
Diese erhalten einen Wert – aber die A"ribute werden nicht modifiziert und bleiben 0.
Häufige Fehler in Konstruktoren
2. Versehentlich für den Konstruktor einen Rückgabewert deklarieren:
public void Point(int initialX, int initialY) { x = initialX;
y = initialY;
}
Nicht die Defini^on eines Konstruktors sondern die Defini^on einer Methode mit Namen Point
Häufige Fehler mit Konstruktoren
3.) Den parameterlosen default Konstruktor verwenden wenn andere Konstruktoren definiert wurden und kein
parameterloser Konstruktor definiert wurde.
class Point { int x; int y;
public Point(int initialX, int initialY) { … } // methods
}
// in the client
Point p = new Point(); 59