4. Objektorientierung I Grundlagen der Programmierung 1 (Java) Fachhochschule Darmstadt Haardtring 100 D-64295 Darmstadt Prof. Dr. Bernhard Humm FH Darmstadt, 11. Oktober 2005
Einordnung im Kontext der Vorlesung 1. Einführung 2. Einfache Programme 3. Kontrollstrukturen 4. Objekt-Orientierung I 5. Algorithmen und Datenstrukturen I 6. Interfaces 7. Rekursion 8. Pakete 10. Software-Qualität 11. Algorithmen und Datenstrukturen II 12. Objektorientierung II 13. Komponenten 14. Design 15. Die Java Klassenbibliothek I 16. Die Java Klassenbibliothek II 17. Software-Kategorien 9. Fehler und Ausnahmen 11.10.2005, Seite 2
Agenda Agenda Klassen und Objekte Vererbung Eclipse 11.10.2005, Seite 3
Wiederholung: Datentypen Datentyp = Wertebereich + Operationen Äpfel können nicht mit Birnen verglichen werden Zentrales Konzept der Informatik Bekannt aus der Mathematik: Gruppen, Körper, Ringe, Algebren Auch Datenstruktur, abstrakter Datentyp genannt In Programmiersprache zusätzlich: Darstellung im Speicher 11.10.2005, Seite 4
Objektorientierung = Programmierung mit Datentypen (Klassen und Objekte) Beispiel: Bruchzahlenklasse class Fraction { f1.mult(f2); int z; // Zähler int n; // Nenner void mult (Fraction f) { this.z = this.z * f.z; this.n = this.n * f.n; mult add void add (Fraction f) { this.z = this.z * f.n + f.z * this.n; this.n = this.n * f.n; z abgeschlossener Baustein n mult und add sind lokal zu Fraction (können auf Fraction-Objekte angewendet werden) this bezeichnet "dieses Objekt", auf das die Operation angewendet wird 11.10.2005, Seite 5
Klassen und Objekte Klasse = Datentyp (wiederkehrendes Muster einzelner Objekte) Objekt = einzelnes Exemplar (Instanz) Objekte werden instanziiert Objekte haben eine Identität (welche Objekte sind gleich?) Notation: UML (Unified Modeling Language) cd Fraction Fraction - numerator: int - denominator: int + add(fraction) : void + mult(fraction) : void Fraction 3/4 Fraction 42/42 Fraction 6/8 11.10.2005, Seite 6
Instanziierung von Klassen: Konstruktoren Spezielle Methoden, die beim Erzeugen eines Objekts automatisch aufgerufen werden class Fraction { int z, n; Fraction (int z, int n) { this.z = z; this.n = n; Fraction () { z = 0; n = 1; void mult (Fraction f) {... void add (Fraction f) {... dienen zur Initialisierung eines Objekts heißen wie die Klasse ohne Funktionstyp und ohne void können Parameter haben können überladen werden Aufruf Fraction f = new Fraction(3, 5); Fraction g = new Fraction(); legt neues Fraction-Objekt an ruft für dieses Objekt den Konstruktor auf 11.10.2005, Seite 7
Attribute (Member Variablen): die Daten des Datentyps Attribute sind die Daten des Datentyps Sie werden deklariert wie die Variablen in einer Methode: Typ Variable [= Ausdruck]; Type kann ein primitiver Datentyp sein oder eine Klasse Sie werden verwendet mit der Punktnotation: Objekt.Variable this (Schlüsselwort) referenziert das aktuelle Objekt class Fraction { int z; // Zähler int n; // Nenner void mult (Fraction f) { this.z = this.z * f.z; this.n = this.n * f.n; void add (Fraction f) { this.z = this.z * f.n + f.z * this.n; this.n = this.n * f.n; 11.10.2005, Seite 8
Weglassen von this class Fraction { int z, n; void mult (Fraction f) { z = z * f.z; n = n * f.n; z und n sind eindeutig. Compiler fügt this automatisch ein void add (Fraction n) { z = z * n.n + this.n * n.z; this.n = this.n * n.n; n wäre nicht eindeutig. Qualifikation mit this nötig this kann weggelassen werden, wenn der restliche Name eindeutig ist 11.10.2005, Seite 9
Methoden: die Operationen des Datentyps Methoden können ausschließlich im Kontext von Klassen deklariert werden: alles bisher gesagte über Methoden gilt class Fraction { int z; // Zähler int n; // Nenner Deklaration: Modifier Rückgabetyp Name (Parameterliste) {Anweisungen Aufruf mit Punktnotation: Objekt.Methode(aktuelle Parameter) void mult (Fraction f) { this.z = this.z * f.z; this.n = this.n * f.n; void add (Fraction f) { this.z = this.z * f.n + f.z * this.n; this.n = this.n * f.n; 11.10.2005, Seite 10
Senden von Nachrichten: Hey object, do something! Der Aufruf von Methoden wird auch als Senden von Nachrichten bezeichnet cd Account Vorstellung: Objekte sind wie Personen der realen Welt, die bestimmte Fähigkeiten haben und Befehle ausführen können withdraw (42) myaccount Customer 11.10.2005, Seite 11
Objektorientierung: Simulation der realen Welt Objektorientes Design und Programmierung bedeutet Objekte der realen Welt modellieren Idee von Simula, der Großmutter aller objektorientierten Sprachen: Simulation der realen Welt Sprachen wie UML erlauben die Modellierung der realen Welt mit graphischen Mitteln cd Bank Customer Product Account Inv oice 11.10.2005, Seite 12
Geheimnisprinzip (Information Hiding): eines der wichtigsten Konzepte des Software Engineering Klassen und Objekte Information Hiding (D.L. Parnas, 1972): Implementierung komplexer Datenstrukturen soll in einer Klasse (Modul) verborgen werden Nutzer erhalten nur eine abstrakte Sicht auf die Daten (abstrakte Datenstrukturen) Datenzugriff nur über die Methoden (Encapsulation = Kapselung) Gekapselte (abstrakte) Datenstrukturen besitzen einen Zustand ("Gedächtnis"), der durch Zugriffsprozeduren geändert werden kann Die Datenkapselung hat folgende Vorteile: Gekapselte Datenstrukturen sind einfacher nutzbar (reduzierte Komplexität) Sie können ohne Auswirkung auf andere Klassen geändert werden Es bestehen jedoch auch Nachteile: Zugriff etwas weniger effizient Eingeschränkte Flexibilität des Zugriffs, da nur über Prozeduren der Schnittstelle auf die Daten zugegriffen werden kann 11.10.2005, Seite 13
Steuerung der Sichtbarkeit: Modifier Modifier: private: nur innerhalb der Klasse sichtbar public: überall sichtbar protected, package scope: Mischformen (später) Gilt für Variablen und Methoden Variablen sollten in der Regel private deklariert werden. Soll lesender und / oder schreibender Zugriff explizit erlaubt werden, dann über Getter / Setter- Methoden class Fraction { private int z; // Zähler private int n; // Nenner public int getz () { return this.z; public int getn () { return this.n; 11.10.2005, Seite 14
Identität und Referenzen Ein Konstruktor-Aufruf stellt Speicherplatz für die Variablen bereit, initialisiert eventuell und gibt stets eine Referenz auf das Objekt zurück (Uniform Reference Semantics) Referenzen sind stets implizit (keine Pointer Arithmetik wie in C / C++) Zuweisung (=) von Objekten ist Zuweisung ihrer Referenzen Gleichheit (==) von Objekten ist Gleichheit der Referenzen class Fraction { int z, n; Fraction (int z, int n) { this.z = z; this.n = n; boolean equals (Fraction f) { return (z == f.z)&&(n==f.n) Fraction f1, f2, f3; boolean b1, b2, b3; f1 = new Fraction(3, 4); f2 = new Fraction(3, 4); f3 = f1; b1 = f1 == f2; // true oder false? b2 = f1 == f3; b3 = f1.equals(f2); 11.10.2005, Seite 15
null: Die Referenz auf kein Objekt null (Schlüsselwort) ist die Referenz auf kein Objekt null kann jeder Variable vom Referenztyp zugewiesen werden null belegt den gleichen Speicherplatz wie eine Objektreferenz Wird eine Methode auf null aufgerufen, so erkennt das der Compiler i. A. nicht Fehler NullPointerException class Fraction { private int z; // Zähler private int n; // Nenner Fraction (int z, int n) { this.z = z; this.n = n; public int getz () { return this.z; Fraction f = null; // auch implizit f.getz() // NullPointerException! f = new Fraction(3, 4); f.getz() // 3 11.10.2005, Seite 16
Call-by-value und Uniform Reference Semantics Wiederholung Methodenaufruf: aktuelle Parameter werden an formale Parameter gebunden (call-by-value) Was ist, wenn der aktuelle Parameter ein Objekt ist? Dann wird die Referenz an den formalen Parameter gebunden (ist nach wie vor call-by-value, wirkt aber wie call-by-reference) Unerwünschte Seiteneffekte können nur passieren, wenn die Objekte nicht gekapselt sind class Weird { void dosideeffect (Fraction f) { int tmp = f.z; f.z = f.n; f.n = tmp; Fraction f = null; Weird w = null; int z = 0; boolean b = false; f = new Fraction(3, 4); z = f.z w = new Weird(); w.dosideeffect(f); b = (z == f.z) // true oder false? 11.10.2005, Seite 17
Überladen von Methoden Signatur = Methodenname + Parameterliste Zwei oder mehrere Methoden können innerhalb eines Gültigkeitsbereichs denselben Namen besitzen, wenn sie eine unterschiedliche Anzahl von Parametern besitzen oder wenn sich die Parametertypen an entsprechender Stelle unterscheiden class Fraction { private int z; // Zähler private int n; // Nenner void mult (Fraction f) { this.z = this.z * f.z; this.n = this.n * f.n; void mult (Fraction f1, Fraction f2) { this.z = this.z * f1.z * f2.z; this.n = this.n * f1.n * f2.n; 11.10.2005, Seite 18
Klassenvariablen und -methoden Bisher betrachtete Variablen und Methoden beziehen sich auf die einzelne Objekte Instanzvariablen / -methoden Variablen, Konstanten und Methoden, die sich auf alle Objekte beziehen Klassenvariablen / Methoden Typische Beispiele: Instanziierung, Suche Keyword in Java: static Häufig werden statt dessen auch Managerklassen verwendet class Customer { // class variables public static int numberofcustomers; // instance variables private String name; // class methods public static Customer makecustomer (String name, ) { public static Customer findcustomer (int number) { // instance methods public void changeaddress (String newadress) { 11.10.2005, Seite 19
Klassen, Objekte, Klassenvariablen, Klassenmethoden, Instanzvariablen, Instanzmethoden Was ist was? Kunde Kundennummer Konto drucke Kontoauszug Kontoauszugsdrucker Anzahl der Kunden führe Zahlungslauf durch hebe Geld ab zahle Geld ein lege neuen Kunden an nimm Kredit auf Kredit suche Kunden Zahlungslauf Mehrwertsteuersatz rechne in Fremdwährung um Betrag Währung Bank IP-Adresse 11.10.2005, Seite 20
Beispiel: Stack und Queue Stack (Kellerspeicher) push(x); fügt x hinten an den Stack an x = pop(); entfernt und liefert hinterstes Stackelement push(3); 3 push(4); 3 4 x = pop(); 3 // x == 4 y = pop(); // y == 3 LIFO-Datenstruktur (last in first out) Queue (Puffer, Schlange) put(x); fügt x hinten an die Queue an x = get(); entfernt und liefert vorderstes Queueelement put(3); 3 put(4); 3 4 x = get(); 4 // x == 3 y = get(); // y == 4 FIFO-Datenstruktur (first in first out) 11.10.2005, Seite 21
Klasse Stack class Stack { int[] data; int top; Stack (int size) { data = new int[size]; top = -1; void push (int x) { if (top >= data.length) Out.println("-- overflow"); else data[++top] = x; int pop () { if (top < 0) { Out.println("-- underflow"); return 0; else return data[top--]; Deklaration eines Array Benutzung top Instanziierung eines Array Schreibender Zugriff auf ein Array Lesender Zugriff auf ein Array data Stack s = new Stack(10); s.push(3); s.push(6); int x = s.pop() + s.pop(); // x == 9 11.10.2005, Seite 22
Klasse Queue class Queue { int[] data; int head, tail; Queue (int size) { data = new int[size]; head = 0; tail = 0; void put (int x) { if ((tail+1) % data.length == head) Out.println("-- overflow"); else { data[tail] = x; tail = (tail+1) % data.length; int get () { if (head == tail) { Out.println("-- underflow"); return 0; else int x = data[head]; head = (head+1) % data.length; return x; tail Benutzung head tail head Queue q = new Queue(10); q.put(3); q.put(6); int x = q.get(); // x == 3 int y = q.get(); // y == 6 data data 11.10.2005, Seite 23
Ausblick zum Weiterdenken Wie werden Objekte auf dem Runtime Stack abgelegt? Was ist ein Heap? Was ist Garbage Collection und wie funktioniert es? 11.10.2005, Seite 24
Agenda Agenda Klassen und Objekte Vererbung Eclipse 11.10.2005, Seite 25
Vererbung Klassifikation Dinge der realen Welt lassen sich oft klassifizieren z.b. Artikel eines Web-Shops Artikel Buch Audio Kamera... HardCover SoftCover ebook CD Cassette Digital Analog Man beachte Ein ebook hat alle Eigenschaften eines Buchs; zusätzlich hat es... Ein Buch hat alle Eigenschaften eines Artikels; zusätzlich hat es... Vererbung CD und Cassette lassen sich gleichermaßen als Audio behandeln Buch, Audio und Kamera lassen sich gleichermaßen als Artikel behandeln 11.10.2005, Seite 26
Vererbung Vererbung class Article { int code; int price; boolean available() {... void print() {... Article(int c, int p) {... Oberklasse Basisklasse Article code price available() print() Article(c, p) class Book extends Article { String author; String title; void print() {... Book(int c, int p, String a, String t) {... Unterklasse erbt: code, price, available, print ergänzt: author, title, Konstruktor überschreibt: print Book author title print() Book(c, p, a, t) Wenn keine Oberklasse angegeben wird, ist sie Object 11.10.2005, Seite 27
Vererbung Überschreiben von Methoden class Article {... void print() { Out.print(code + " " + price); class Book extends Article {... void print() { super.print(); Out.print(" " + author + ": " + title); Article(int c, int p) { code = c; price = p; Book(int c, int p, String a, String t) { super(c, p); author = a; title = t; Benutzung Book book = new Book(code, price, author, title); erzeugt Book-Objekt Book-Konstruktor Article-Konstruktor (code = c; price = p;) author = a; title = t; book code price author title book.print(); print aus Book print aus Article Out.print(...); code price author: title Ausgabe: code price author: title 11.10.2005, Seite 28
Vererbung Klassenhierarchien Article code price available() print() Jedes Buch ist ein Artikel Aber: nicht jeder Artikel ist ein Buch Book author title print() Audio songs print() Camera supplier print()... CD tracks Cassette lengh... print() print() 11.10.2005, Seite 29
Vererbung Kompatibilität zwischen Klassen Unterklassen sind Spezialisierungen ihrer Oberklassen Book-Objekte können Article-Variablen zugewiesen werden Article a = new Book(code, price, author, title); a code price author title nur Article-Felder sind über a zugreifbar a.code a.price if (a instanceof Book) Book b = (Book) a; // Laufzeittyptest // Typumwandlung mit Laufzeittypprüfung b code price author title alle Book-Felder sind über b zugreifbar b.code b.price b.author b.title 11.10.2005, Seite 30
Vererbung Dynamische Bindung Heterogene Datenstruktur Article[] a; Article available() print() Book CD Book CD Camera Book Audio Camera Alle Varianten können als Artikel behandelt werden print() print() print() void printarticles() { for (int i = 0; i < a.length; i++) { if (a[i].available()) { a[i].print(); ruft geerbtes available() aus Article auf ruft je nach Artikelart das print() aus Book, CD oder Camera auf Dynamische Bindung obj.print() ruft die print-methode des Objekts auf, auf das obj gerade zeigt 11.10.2005, Seite 31
Agenda Agenda Klassen und Objekte Vererbung Eclipse 11.10.2005, Seite 32
Eclipse Die integrierte Enwicklungsumgebung Eclipse http://www.eclipse.org/ 11.10.2005, Seite 33