Polymorphie (Vielgestaltigkeit)

Slides:



Advertisements
Ähnliche Präsentationen
Blue J.
Advertisements

der Universität Oldenburg
der Universität Oldenburg
der Universität Oldenburg
Progwerkstatt JAVA Klasse, Objekte, Konstruktoren, Methoden
Java: Objektorientierte Programmierung
Java: Dynamische Datentypen
Indirekte Adressierung
FH-Hof Verwaltung von Zeichenketten Richard Göbel.
Java: Referenzen und Zeichenketten
Java: Grundlagen der Objektorientierung
Vererbung.
SWITCH - Anweisung.
Abstrakte Klassen.
Klassenvariable (auch Klassendaten bzw. statische Attribute genannt) und statische Methoden.
ARRAY oder FELD oder VEKTOR
Ein Beispiel in Java.
Dynamisches Array als "verkettete Liste". Ein Vergleich.
Erweiterte Zuweisungskompatibilität
Dynamischer Speicher und Struktur
Pointer. Grundsätzliches: Im Arbeitsspeicher werden Daten gespeichert. Um auf die Daten eindeutig zugreifen zu können, werden diesen Daten Adressen zugeordnet.
Klassenvariable. Da man für jede Kuh bzw. jede Henne auf dem Markt den gleichen Preis für ein Liter Milch, bzw. den gleichen Preis für ein Ei bekommt,
Konstruktoren.
Objekte werden als Adressen (Referenzen) übergeben. Dies führt manchmal zu unerwarteten Ergebnissen...
Assoziationen (Beziehungen) 1 : n. Zu einem Auto gibt es mehrere Fahrer (2) und zu diesen 2 Fahrern gibt es genau dieses Auto.
Polymorphie (Vielgestaltigkeit)
Assoziationen (Beziehungen). Zwischen Objekten kann es eine Beziehung geben.
Objekte und Arbeitsspeicher
V AdresseWert public static void main(...){ int[] v; v=new int[2]; } Was veranlasst diese Anweisung im Arbeitsspeicher ? Es wird im Arbeitsspeicher.
Interface bzw. Schnittstelle anschaulich: Hüllenklasse
FOR Anweisung. Aufgabe : Ausgabe aller ganzen Zahlen von 0 bis 100 auf dem Bildschirm.
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
DO...WHILE Anweisung.
ARRAY oder FELD oder VEKTOR
Praktikum Entwicklung und Einsatz von Geosoftware I - Sitzung 3 Klassen, Objekte, Arrays und Kontrollstrukturen Sommersemester 2003 Lars Bernard.
Einführung in die Programmierung mit Java
Java-Kurs - 7. Übung Besprechung der Hausaufgabe Referenzvariablen
Programmieren mit JAVA
PRJ 2007/1 Stefan Dissmann Motivation Problem: gleiche Datenstrukturen werden für verschiedene Objekte gebraucht: z.B. Listen von Studierenden, Kunden,
PKJ 2005/1 Stefan Dissmann Ausblick Es fehlen noch: Möglichkeiten zum Strukturieren größerer Programme Umgang mit variabler Zahl von Elementen Umgang mit.
PKJ 2005/1 Stefan Dissmann Zusammenfassung Vorwoche Programm besteht aus mehreren Bestandteilen: Schlüsselwörter Sonderzeichen Bezeichner Kommentare Texte.
Zusammenfassung Vorwoche
PKJ 2005/1 Stefan Dissmann Zusammenfassung Vorwoche Methoden sind mit einem Namen versehene Programmabschnitte besitzen Rückgabetyp, Namen, Parameterliste.
Die Skriptsprache Perl (8) Wolfgang Friebel DESY Zeuthen.
DVG Einführung in Java1 Einführung in JAVA.
Variablenkonzept Klassisch, in Java Basistyp
Aufruf einer Methode eines Objektes vom Typ „Bruch“
Optimale Ursprungsgerade
CuP - Java Vierte Vorlesung Entspricht ungefähr Kapitel 2.1 des Skriptums Montag, 14. Oktober 2002.
Programmiervorkurs WS 2014/15 Instanzmethoden
Programmiervorkurs WS 2014 Referenzdatentypen
CuP - Java Achte Vorlesung Entspricht ungefähr Kapitel 4.1 des Skriptums Montag, 28. Oktober 2002.
Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.
early binding (frühe Bindung) late binding (späte Bindung)
Informatik I : Software höhere Programmiersprachen Java Klassen: hat Methoden (Funktionen) und Daten (Variablen) es kann mehrere Klassen geben nur eine.
A Workshop About this chapter General description Units Time Schedule
Einführung in die Programmierung mit Java
Erweiterte Zuweisungskompatibilität. Wie kann man Objekte verschiedener Klassen einer Klassenhierarchie einander zuweisen ?
Funktionen. Aufgabe : Eingabe zweier Zahlen ---> Minimum bestimmen Dann nochmals Eingabe zweier Zahlen ---> Minimum bestimmen.
Pointer. Grundsätzliches: Im Arbeitsspeicher werden Daten gespeichert. Um auf die Daten eindeutig zugreifen zu können, werden diesen Daten Adressen zugeordnet.
Tutorium Software-Engineering SS14 Florian Manghofer.
Java Programme nur ein bisschen objektorientiert.
Tutorium Software-Engineering SS14 Florian Manghofer.
Tutorium Software-Engineering SS14 Florian Manghofer.
Tutorium Software-Engineering SS14 Florian Manghofer.
Konstruktoren.
ARRAY oder FELD oder VEKTOR
Grundkurs Informatik 11-13
Es gibt Klassen, die mit der Entwicklungsumgebung ausgeliefert werden
Implementieren von Klassen
 Präsentation transkript:

Polymorphie (Vielgestaltigkeit)

Anschaulich: Ein Amphibienfahrzeug kann verschiedene Gestalten annehmen: - Fahrzeug zu Wasser - Fahrzeug an Land - Fahrzeug in der Luft

Egal, wo sich der Fahrer gerade befindet, passt sich das Amphibienfahrzeug automatisch (d.h. von selbst, ohne Zutun des Fahrers) der Situation an: Im Wasser werden automatisch die Fenster geschlossen: Das Amphibienfahrzeug bekommt die Gestalt eines Boots.

In der Luft werden automatisch die Flügel ausgefahren In der Luft werden automatisch die Flügel ausgefahren. Das Amphibienfahrzeug bekommt die Gestalt eines Flugzeugs. Auf dem Land werden automatisch die Räder benutzt. Das Amphibienfahrzeug bekommt die Gestalt eines Autos. Das nennt man Vielgestaltigkeit

Wenn eine Methode, wie z. B Wenn eine Methode, wie z.B. getTierwert() für verschiedene Programmteile steht (und z.B. einmal den Tierwert (= Marktwert) verschiedener Klassen wie z.B. Henne oder das andere Mal Kuh berechnen kann), dann nennt man dies Polymorphie

Beispiel: Der Tierwert einer Henne berechnet sich aus dem 2-fachen ihrer Legeleistung. Der Tierwert einer Kuh berechnet sich aus dem 100-fachen ihrer Milchleistung.

Aus Gründen der Vereinfachung soll die Klasse Kuh nur das Attribut double milchLeistung und die Klasse Henne nur das Attribut int legeLeistung besitzen.

Aus den gleichen Gründen werden die zugehörigen get- und set-Methoden weggelassen, die später beim Programmieren am Rechner natürlich implementiert werden.

Beispiel: In einem Feld sollen verschiedene Objekte (Tiere), (hier: Hennen oder Kühe) abgespeichert und dann deren spezifischer Tierwert auf dem Bildschirm ausgegeben werden

Die Reihenfolge der Objekte (Hennen bzw Die Reihenfolge der Objekte (Hennen bzw. Kühe) in dem Feld soll vom Anwender bestimmt werden bzw. zufällig sein.

Aber Halt: In einem Feld können nur Objekte der gleichen Klasse gespeichert werden.

Deswegen muß man eine Oberklasse von Henne und Kuh erzeugen Deswegen muß man eine Oberklasse von Henne und Kuh erzeugen. Dann muss man Objekten der Oberklasse, Objekte der Unterklassen Henne oder Kuh zuweisen und die Objekte der Oberklasse im Feld speichern.

Vorgehensweise: Man erzeugt die Klassen Henne und Kuh mit jeweils der spezifischen getTierwert () Methode, die den spezifischen Tierwert einer Henne bzw. einer Kuh erzeugt (mit return zurück gibt).

Dann erzeugt man eine gemeinsame Basisklasse, z. B Dann erzeugt man eine gemeinsame Basisklasse, z.B. mit dem Namen Nutztier der Klassen Henne und Kuh.

In UML-Darstellung:

Nutztier Henne Kuh + getTierwert (): double + getTierwert (): double Aus Platzgründen (und um nur das Wichtigste darzustellen) werden hier (und bei einigen anderen Folien) im UML nur die Methoden (und nicht auch noch die Attribute) dargestellt ...

Mit new werden (in einer Schleife) jeweils eine Henne bzw Mit new werden (in einer Schleife) jeweils eine Henne bzw. eine Kuh erzeugt und einem Element des Feldes (mit dem Typ Nutztier) zugewiesen.

Nutztier nutztiere h1 k1 k2 k3 h2 h3 Es werden zufallsbestimmt jeweils entweder eine Henne oder eine Kuh in das Array nutztiere der Klasse Nutztier eingefügt. Der Programmierer will jetzt die Tierwerte der Nutztiere auf dem Bildschirm ausgeben. Und jetzt die wunderbare Eigenschaft der Polymorphie: Der Programmierer muss nicht in einer Schleife jedes Mal überprüfen, ob es sich um eine Henne oder eine Kuh handelt und dann die entsprechende Methode aufrufen, die den spezifischen Tierwert des jeweiligen Nutztiers holt, sondern .... Das Programm weiß von selbst, welche Methode es von welcher Klasse (Henne oder Kuh) aufrufen muss!!

Als Programm-Skizze

Bemerkung: Der Einfachheit halber ist die Reihenfolge der Hennen bzw Bemerkung: Der Einfachheit halber ist die Reihenfolge der Hennen bzw. Kühe in der folgenden Programm-Skizze nicht zufällig bzw. vom Anwender vorgegeben und außerdem ist die Schleife weggelassen worden.

Nutztier[] nutztiere; Es wird Speicher für eine Referenz (Pointer) auf das Array nutztiere reserviert. n.. Ganz wichtig: n.. ist hier und in den folgenden Folien eine Abkürzung für nutztiere (weil sonst der Platz nicht ausreicht)

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; Da nutztiere eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für eine Referenz (Pointer) auf das Array nutztiere reserviert. Es wird Speicher für das Array nutztiere reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Ein Feld ist in Java als ein Objekt (mit new) realisiert. Dieses Feld besteht hier aus 2 (Standardvorbelegung: null) Zeigern auf Nutztiere. n.. 0120 ? n..[0] 0470 null Auf die (Anfangs)Adresse dieser Speicherbereiche hat der Programmierer keinen Einfluß. Diese legt der Interpreter bzw. Programmlader fest. n..[1] ... null

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; Da nutztiere eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für eine Referenz (Pointer) auf das Array nutztiere reserviert. Es wird Speicher für das Array nutztiere reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Ein Feld ist in Java als ein Objekt (mit new) realisiert. Dieses Feld besteht hier aus 2 (Standardvorbelegung: null) Zeigern auf Nutztiere. n.. 0120 ? n..[0] 0470 null Welchen Wert muss nutztiere bekommen, damit es auf das gerade angelegte Objekt zeigt? n..[1] ... null

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; Da nutztiere eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für eine Referenz (Pointer) auf das Array nutztiere reserviert. Es wird Speicher für das Array nutztiere reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Ein Feld ist in Java als ein Objekt (mit new) realisiert. Dieses Feld besteht hier aus 2 (Standardvorbelegung: null) Zeigern auf Nutztiere. n.. 0120 n..[0] 0470 null Welchen Wert muss nutztiere bekommen, damit es auf das gerade angelegte Objekt zeigt? n..[1] ... null

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; Da nutztiere eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für eine Referenz (Pointer) auf das Array nutztiere reserviert. Es wird Speicher für das Array nutztiere reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Ein Feld ist in Java als ein Objekt (mit new) realisiert. Dieses Feld besteht hier aus 2 (Standardvorbelegung: null) Zeigern auf Nutztiere. n.. 0120 0470 n..[0] 0470 null Welchen Wert muss nutztiere bekommen, damit es auf das gerade angelegte Objekt zeigt? n..[1] ... null

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Zur Wiederholung: Hier wird nicht die Zeichenkette "Ute" abgespeichert, sondern die Adresse der Zeichenkette "Ute" nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für das Objekt erzeugt, auf das nutztiere [0] zeigen soll. Welchen Inhalt hat diese Adresse und wer legt diesen fest? Es sind die Werte des neu angelegten Tieres, die durch den Aufruf des Konstruktors festgelegt werden. n.. 0120 0470 n..[0] 0470 null n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); Welchen Wert muss nutztiere[0] bekommen, damit es auf das gerade angelegte Objekt zeigt? n.. 0120 0470 n..[0] 0470 null n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); Welchen Wert muss nutztiere[0] bekommen, damit es auf das gerade angelegte Objekt zeigt? n.. 0120 0470 n..[0] 0470 n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); Welchen Wert muss nutztiere[0] bekommen, damit es auf das gerade angelegte Objekt zeigt? n.. 0120 0470 n..[0] 0470 0700 n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für das Objekt erzeugt, auf das nutztiere [1] zeigen soll. n.. 0120 0470 0600 ... n..[0] 0470 0700 n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); Welche Inhalte stehen an dieser Adresse und wer legt diese fest? n.. 0120 0470 0600 Elsa ... 50 n..[0] 0470 0700 n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); Es sind die Werte des neu angelegten Tieres, die durch den Aufruf des Konstruktors festgelegt werden. n.. 0120 0470 0600 Elsa ... 50 n..[0] 0470 0700 n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Zur Wiederholung: Hier wird nicht die Zeichenkette "Elsa" abgespeichert, sondern die Adresse der Zeichenkette "Elsa" nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); Welchen Wert muss nutztiere[1] bekommen, damit es auf das gerade angelegte Objekt zeigt? n.. 0120 0470 0600 Elsa ... 50 n..[0] 0470 0700 n..[1] ... null 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); n.. 0120 0470 0600 Elsa ... 50 n..[0] 0470 0700 n..[1] ... 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); n.. 0120 0470 0600 Elsa ... 50 n..[0] 0470 0700 n..[1] ... 0600 0700 Ute ... 1

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); nutztiere[0].getTierwert(); nutztiere[1].getTierwert(); Man kann nur dann die Methode eines Objekts (über die Referenzvariable) aufrufen, wenn die Klasse dieses Objekts diese Methode besitzt. Dies ist Aufgabe des Compilers. Z.B. prüft der Compiler nach, ob bei der Anweisung nutztiere[1].getTierwert() die Klasse Nutztier die Methode getTierwert() besitzt.

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); nutztiere[0].getTierwert(); nutztiere[1].getTierwert(); Welche getTierwert() Methode wird nun in nutztiere[0] bzw. nutztiere[1] aufgerufen? 1) getTierwert() in der Klasse Nutztier 2) getTierwert() in der Klasse Henne 3) getTierwert() in der Klasse Kuh Welche 3 Möglichkeiten kann es geben?

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); nutztiere[0].getTierwert(); nutztiere[1].getTierwert(); Es wird nicht die Methode der Referenzvariablen nutztiere, also getTierwert() der Klasse Nutztier, sondern die Methode der Klasse des Objekts, auf das die Referenzvariable nutztiere (nutztiere[0], nutztiere[1], ...) zeigt, also hier getTierwert() der Klasse Henne bzw. getTierwert() der Klasse Kuh.

Nutztier[] nutztiere; nutztiere=new Nutztier[2]; nutztiere[0]=new Henne("Ute", 1); nutztiere[1]=new Kuh("Elsa", 50); nutztiere[0].getTierwert(); nutztiere[1].getTierwert(); Noch genauer: Es wird die Methode des Objekts aufgerufen, die in der Vererbungshierarchie am niedersten ist. Also: Wenn es in der Klasse Henne die Methode getTierwert() gibt, wird diese aufgerufen, sonst die Methode getTierwert() der Klasse Nutztier. Wenn es in der Klasse Kuh die Methode getTierwert() gibt, wird diese aufgerufen, sonst die Methode getTierwert() der Klasse Nutztier.

nutztiere[0].getTierwert()); System.out.println( nutztiere[0].getTierwert()); System.out.println( nutztiere[1].getTierwert()); Was macht also: nutztiere[0]. getTierwert(); Tierwert 2 *1, also 2 der Henne zurückgeben. Was macht also: nutztiere[1]. getTierwert() Tierwert 100*50 = 5000 der Kuh zurückgeben.

Das exakte Programm:

public class MainPoly{ public static void main(String[] args){ double zufall; int i; double wert; Nutztier[] nutztiere; nutztiere=new Nutztier[2];

for(i=0;i<2;i++){ zufall = Math.random(); if (zufall<0.5){ nutztiere[i] = new Henne("Ute", 1); } else{ Kuh("Elsa", 50);

for(i=0;i<2;i++){ wert = nutztiere[i]. getTierwert(); System.out.println( "Tierwert:" + wert); } nutztiere[i] tritt verschiedengestaltig auf, wobei die zugehörige Methode gleichen Namens etwas anderes macht! Wir nennen diese Version der Polymorphie: "polymorphe Methode"

class Nutztier{ private String name; public Nutztier( String pName){ name = pName; } public double getTierwert(){ return 123;

class Kuh extends Nutztier{ private double milchLeistung; public Kuh(String pName, double pMilchLeistung){ super(pName); milchLeistung=pMilchLeistung; } public double getTierwert(){ return(100* milchLeistung);

class Henne extends Nutztier{ private int legeLeistung; public Henne(String pName, int pLegeLeistung){ super(pName); legeLeistung=pLegeLeistung; } public double getTierwert(){ return(2 * legeLeistung);

Nochmals zur Klasse Nutztier

public double getTierwert(){ return 123; class Nutztier{ private String name; public Nutztier( String pName){ name = pName; } public double getTierwert(){ return 123; Die Methode getTierwert() wird unbedingt benötigt, auch wenn sie aus keinen Anweisungen bestehen würde. Diese Methode wird ja im Ausdruck nutztiere[i].getTiertwert() benutzt (und von den Methoden getTierwert() der Unterklassen Henne und Kuh überschrieben). Wo wird die Methode getTierwert() der Klasse Nutztier in diesem Programm aufgerufen? Nirgends Wann würde sie aufgerufen werden? Konstruieren Sie einen Fall. Wenn ein überarbeiteter Programmierer vergessen hätte in der Klasse Henne oder Kuh die Methode getTierwert() zu implementieren. Dann wird in der Oberklasse nach dieser Methode gesucht (überschreiben). Der Compiler unterstützt also nicht den vergesslichen Programmierer. Was müsste man ändern, damit der vergessliche Programmierer vom Compiler unterstützt wird?

public double getTierwert(){ return 123; class Nutztier{ private String name; public Nutztier( String pName){ name = pName; } public double getTierwert(){ return 123; Die Methode getTierwert() in der Klasse Nutztier muss abstract gemacht werden (d.h. es wird nur der Methodenkopf angegeben). Die Methoden müssen dann in den Unterklassen Henne und Kuh implementiert (ausprogrammiert) werden.

abstract class Nutztier{ private String name; public Nutztier( String pName){ name = pName; } abstract public double getTierwert(){ return 123; Übrigens.... Was ist falsch an diesem Programm? Alles andere im Vergleich zum vorigen Programm bleibt gleich, nur die Bezeichnung abstract wird eingefügt und der Methodenkörper entfernt

abstract class Nutztier{ private String name; public Nutztier( String pName){ name = pName; } abstract public double getTierwert(); Es wird nur der Methodenkopf angegeben.

Diskussion: Was soll Polymorphie Diskussion: Was soll Polymorphie? Man kann das doch auch "traditionell" lösen, oder? Das macht man doch wie folgt:

public class MainOhnePoly{ public static void main(String[] args){ double zufall; int i; double wert; Nutztier[] nutztiere; nutztiere=new Nutztier[2]; Alles gleich wie vorher

zufall = Math.random(); if (zufall<0.5){ nutztiere[i] = new for(i=0;i<2;i++){ zufall = Math.random(); if (zufall<0.5){ nutztiere[i] = new Henne("Ute", 1); } else{ Kuh("Elsa", 50); Alles gleich wie vorher

for(i=0;i<2;i++){ wert = nutztiere[i]. getTierwert(); System.out.println( "Tierwert:" + wert); } Alles gleich wie vorher

class Kuh extends Nutztier{ private double milchLeistung; public Kuh(String pName, double pMilchLeistung){ super(pName); milchLeistung=pMilchLeistung; } /* public double getTierwert(){ return(100* milchLeistung); */ Alles gleich wie vorher, außer dass getTierwert() entfernt wird

class Henne extends Nutztier{ private int legeLeistung; public Henne(String pName, int pLegeLeistung){ super(pName); legeLeistung =pLegeLeistung; } /* public double getTierwert(){ return(2 * legeLeistung); */ Alles gleich wie vorher, außer dass getTierwert() entfernt wird

public Nutztier(String pName){ name = pName; } class Nutztier{ private String name; public Nutztier(String pName){ name = pName; } Alles gleich wie vorher

public double getTierwert() { if(this instanceof Henne){ return (2*((Henne)this) .getLegeLeistung()); } if(this instanceof Kuh){ return (100*((Kuh) this) .getMilchLeistung()); return 0; testet, ob das Objekt den Typ Henne hat. testet, ob das Objekt den Typ Kuh hat.

Nachteile der Nicht-Polymorphie-Lösung: public double getTierwert() { if(this instanceof Henne){ return (2*((Henne)this) .getLegeLeistung()); } if(this instanceof Kuh){ return (100*((Kuh) this) .getMilchLeistung()); return 0; Nachteile der Nicht-Polymorphie-Lösung: Im Vergleich zur Polymorphie-Lösung, muss man eine Fallunterscheidung machen. Das könnte sich ein Programmierer schon antun, aber es gibt auch Fälle, die ohne Polymorphie nicht zu lösen sind. Betrachten wir dazu folgenden Fall:

Man hat den ähnlichen Fall wie im letzten Programm: Henne, Kuh und Nutztier. Ein Unternehmer lässt die Klasse AMS entwickeln (diese steht für Agricultural Management System, (deutsch: Landwirtschaftliches Verwaltungsprogramm), die jeder Programmierer (der Bauern als Kunden hat), als package ("Library"), d.h. ohne Quellcode, besitzen sollte und in der wertvolle Methoden für die Verwaltung seines Bauernhofs enthalten sind. Unter anderem enthält die Klasse AMS die Klassenmethode, die den mittleren Tierwert von einem Array von Nutztieren berechnet.

Des Weitern enthält AMS eine Klassenmethode, die das beste Nutztier (das mit dem größten Tierwert) eines Arrays von Nutztieren ermittelt und eine Klassenmethode, die den Index dieses besten Nutztiers (bezogen auf das Array), ermittelt. Die Methoden von AMS benötigen also noch folgendes: eine Methode getTierwert(), die den Wert eines Tieres berechnet. Diese Methode getTierwert() muss in jeder Unterklasse von Nutztier implementiert werden.

Wenn sich der Bauer also ein neues Nutztier, z. B Wenn sich der Bauer also ein neues Nutztier, z.B. ein Schwein zulegt, muss nur noch eine Methode getTierwert() in der Klasse Schwein implementiert werden und diese Klasse Schwein muss von Nutztier erben. Ohne die Verwendung von Polymorphie ist dieser Fall nicht zu lösen, da der Programmierer nicht den Quellcode der Klasse AMS besitzt, sondern nur das package gekauft hat.

Beispiel: Es müssen die Klassen Kuh, Henne, Nutztier (wie vorher, also mit jeweils der Methode printAllAttributs()) und AMS erstellt werden. In main soll ein Feld von Nutztieren angelegt werden und von allen Klassenmethoden von AMS aufgerufen werden.

public Nutztier(String pname) { name = pname; } class Nutztier { private String name; public Nutztier(String pname) { name = pname; } public double getTierwert() { return 123; public void setName(String pName) { name = pName; public String getName() { return (name); Was könnte man in der Klasse Nutztier– vom Design her betrachtet – besser machen ? Methode getTiertwert(...) abstract machen

public void printAllAttributs() { System.out.println("Hallo Nutztier"); } polymorphe Methode: d.h. die Methode, die bei den polymorphen Objekten verschieden implementiert wird.

class Kuh extends Nutztier { private double milchLeistung; public Kuh(String pN, double pM){ super(pN); milchLeistung = pM; } public double getMilchLeistung() { return milchLeistung; public void setMilchLeistung(double pM) { this.milchLeistung = pM;

public double getTierwert(){ return (100 * milchLeistung); } public void printAllAttributs(){ System.out.println("Kuhname=" + getName() + " Milchleistung=" + milchLeistung); polymorphe Methode polymorphe Methode

class Henne extends Nutztier { private int legeLeistung; public Henne(String pName, int pL){ super(pName); legeLeistung = pL; } public int getLegeLeistung() { return legeLeistung; public void setLegeLeistung(intpL){ this.legeLeistung = pL;

public double getTierwert(){ return (2 * legeLeistung); } public void printAllAttributs() { System.out.println("Hennename=" + getName() + " Legeleistung=" + legeLeistung); polymorphe Methode polymorphe Methode

ACHTUNG: In der nächsten Folie werden die Namen der Methoden (aus Platzgründen) stark gekürzt. Bitte NICHT nachmachen, sondern ausführliche Namen vergeben wie z.B: berechneMittlerenTierwert(...) berechneIndexMaximalerTierwert(...) berechneMaximalerTierwert(...)

static double mittlereTW(Nutztier[] pNutztiere){ int i; class AMS{ static double mittlereTW(Nutztier[] pNutztiere){ int i; double summe=0; double mittel; for(i=0;i<pNutztiere.length;i++){ summe=summe+ pNutztiere[i].getTierwert(); } mittel=summe/pNutztiere.length; return mittel; pNutztiere[i] tritt verschiedengestaltig auf (als Henne oder Kuh)

static int indexMaxTW(Nutztier[] pNutztiere){ int i; int indexMax=0; for(i=0;i<pNutztiere.length;i++){ if(pNutztiere[indexMax].getTierwert() < pNutztiere[i].getTierwert()){ indexMax=i; } return indexMax; pNutztiere[...] tritt verschiedengestaltig auf (als Henne oder Kuh)

static Nutztier maxTW(Nutztier[] pNutztiere){ int i; int indexMax=0; for(i=0;i<pNutztiere.length;i++){ if(pNutztiere[indexMax].getTierwert() < pNutztiere[i].getTierwert()){ indexMax=i; } return pNutztiere[indexMax]; pNutztiere[...] tritt verschiedengestaltig auf (als Henne oder Kuh)

package uepolymorphiebauernhof10; public class MainUePolymorphieBauernhof10 { public static void main(String[] args){ int i; int index; double wert; String name; double milchleistung; int legeleistung; Nutztier nutztier; Nutztier[] nutztiere;

nutztiere = new Nutztier[2]; Henne("Ute",3); nutztiere[1] = new Kuh("Elsa",200);

for(i=0; i<nutztiere.length; i++){ if(nutztiere[i] instanceof Henne){ name=((Henne)nutztiere[i]).getName(); legeleistung=((Henne)nutztiere[i]). getLegeLeistung(); System.out.println("Name= "+name +" Legeleistung= "+legeleistung); } Wenn dies der Fall ist, kann der Typ von nutztiere[i] in den Typ Henne downgecastet werden (d.h. der Obertyp in den Untertyp umgewandelt werden instanceof prüft ab, ob nutztiere[i] eine Instanz (d.h. ein Objekt) der Klasse Henne ist. Ohne Polymorphie muss man leider Fallunterscheidungen machen, um die Attribute der Kühe und Hennen auszugeben.

if(nutztiere[i] instanceof Kuh){ name=((Kuh)nutztiere[i]).getName(); milchleistung=((Kuh)nutztiere[i]). getMilchLeistung(); System.out.println("Name= "+name +" Milchleistung= "+milchleistung); } Ohne Polymorphie muss man leider Fallunterscheidungen machen, um die Attribute der Kühe und Hennen auszugeben.

for (i=0; i<nutztiere.length; i++){ Wie könnte man die Ausgabe mittels Polymorphie weniger aufwendig gestalten ? Wie kann man die Tierwerte der einzelnen Nutztiere ausgeben? for (i=0; i<nutztiere.length; i++){ nutztiere[i].printAllAttributs(); } for (i=0; i<nutztiere.length; i++){ System.out.println("Name= " + nutztiere[i].getName()); System.out.println("Tierwert = " + nutztiere[i].getTierwert()); }

for (i=0; i<nutztiere.length; i++){ nutztiere[i] tritt verschiedengestaltig auf (als Henne oder Kuh) "polymorphe Methode" for (i=0; i<nutztiere.length; i++){ nutztiere[i].printAllAttributs(); } for (i=0; i<nutztiere.length; i++){ System.out.println("Name= " + nutztiere[i].getName()); System.out.println("Tierwert = " + nutztiere[i].getTierwert()); }

index=AMS.indexMaxTW(nutztiere); wert=AMS.mittlereTW(nutztiere); nutztier=AMS.maxTW(nutztiere); System.out.println("index bestes Tier= " + index); System.out.println("bestes Tier= "+ nutztier.getName()+ " " + nutztier.getTierwert()); System.out.println("Mittelwert der Nutztiere = " + wert); }

index=AMS.indexMaxTW(nutztiere); wert=AMS.mittlereTW(nutztiere); nutztier=AMS.maxTW(nutztiere); System.out.println("index bestes Tier= " + index); System.out.println("bestes Tier= "+ nutztier.getName()+ " " + nutztier.getTierwert()); System.out.println("Mittelwert der Nutztiere = " + wert); } nutztiere tritt verschiedengestaltig auf (als Henne oder Kuh) Wir nennen diese Version der Polymorphie: "polymorpher Parameter"

index=AMS.indexMaxTW(nutztiere); wert=AMS.mittlereTW(nutztiere); nutztier=AMS.maxTW(nutztiere); System.out.println("index bestes Tier= " + index); System.out.println("bestes Tier= "+ nutztier.getName()+ " " + nutztier.getTierwert()); System.out.println("Mittelwert der Nutztiere = " + wert); } nutztier tritt verschiedengestaltig auf (als Henne oder Kuh) Wir nennen diese Version der Polymorphie: "polymorphe Rückgabe"

index=AMS.indexMaxTW(nutztiere); wert=AMS.mittlereTW(nutztiere); nutztier=AMS.maxTW(nutztiere); System.out.println("index bestes Tier= " + index); System.out.println("bestes Tier= "+ nutztier.getName()+ " " + nutztier.getTierwert()); System.out.println("Mittelwert der Nutztiere = " + wert); } "polymorphe Methode" nutztier tritt verschiedengestaltig auf (als Henne oder Kuh)

index=AMS.indexMaxTW(nutztiere); wert=AMS.mittlereTW(nutztiere); nutztier=AMS.maxTW(nutztiere); System.out.println("index bestes Tier= " + index); System.out.println("bestes Tier= "+ nutztier.getName()+ " " + nutztier.getTierwert()); System.out.println("Mittelwert der Nutztiere = " + wert); } Ist getName() auch eine polymorphe Methode? Ja, aber... ... getName() wurde nicht in den Unterklassen Henne und Kuh implementiert (programmiert). Deswegen erben die Unterklassen die Methode getName() der Oberklasse Nutztier und sind deswegen gleich !

Zusammenfassung Es gibt drei verschiedene Erscheinungsformen der Polymorphie: r = obj.methode(p) polymorpher Parameter : p ist ein Objekt und kann verschiedenen Datentyps sein (z.B. Henne oder Kuh) polymorphe Methode : je nachdem, welchen Datentyp obj hat (z.B. Henne oder Kuh), wird eine Methode gleichen Namens aufgerufen, wie z.B: obj.getTierwert(). Bem: obj kann auch eine Klasse sein (z.B: AMS) polymorpher Rückgabewert (r ist ein Objekt und kann verschiedenen Datentyps sein (z.B. Henne oder Kuh)