Polymorphie (Vielgestaltigkeit)

Slides:



Advertisements
Ähnliche Präsentationen
der Universität Oldenburg
Advertisements

Imperative Programmierung
der Universität Oldenburg
Imperative Programmierung
Indirekte Adressierung
FH-Hof Indirekte Adressierung Richard Göbel. FH-Hof Einfache Speicherung von Daten Eine "einfache" Deklaration definiert direkt eine Speicherplatz für.
Java: Grundlagen der Objektorientierung
Vererbung.
SWITCH - Anweisung.
Abstrakte Klassen.
Klassenvariable (auch Klassendaten bzw. statische Attribute genannt) und statische Methoden.
Strukturen. In einer Struktur kann eine beliebige Anzahl von Komponenten (Daten) mit unterschiedlichen Datentypen (im Gegensatz zu Feldern) zusammengefaßt.
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.
Assoziationen (Beziehungen). Zwischen Objekten kann es eine Beziehung geben.
Polymorphie (Vielgestaltigkeit)
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
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
ARRAY oder FELD oder VEKTOR
Einführung in die Programmierung mit Java
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.
Packages Vortrag : Cornelia Hardt 23. November 1999.
DVG Einführung in Java1 Einführung in JAVA.
OOP-Begriffe Abstraktion Modellieren Klasse Objekt Attribute Methoden
Variablenkonzept Klassisch, in Java Basistyp
Optimale Ursprungsgerade
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.
OOP-Begriffe Abstraktion Modellieren Klasse Objekt Attribute Methoden
Java-Kurs - 3. Übung Hausaufgabe Arrays For-Schleifen.
Java-Kurs Übung Besprechung der Hausaufgabe Vererbung
Java-Kurs Übung Besprechung der Hausaufgabe Vererbung
Einführung in die Programmierung mit Java
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer, Dr. Gerhard Gröger Einführung in die Programmierung mit Java 5. Vorlesung WS 2002/2003.
Erweiterte Zuweisungskompatibilität. Wie kann man Objekte verschiedener Klassen einer Klassenhierarchie einander zuweisen ?
Objektorientierte Programmierung (OOP)
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.
Vererbung in Java. public abstract class Form { protected int breite; protected int hoehe; protected String farbe; /** * Erzeuge eine Form der Breite.
Konstruktoren.
Venusspiegel und Marsschild
ARRAY oder FELD oder VEKTOR
Java-Kurs Übung Klassen und Objekte: Vererbung (Fortsetzung)
Einführung in die Programmierung mit Java
Grundkurs Informatik 11-13
Von Cem, Maurice und lars
Arrays in Java Ein Array ist eine Variable, die aus einer An-zahl von Elementen des gleichen Datentyps besteht, die aufeinanderfolgend im Speicher liegen.
Es gibt Klassen, die mit der Entwicklungsumgebung ausgeliefert werden
Arrays in Java Ein Array ist eine Variable, die aus einer An-zahl von Elementen des gleichen Datentyps besteht, die aufeinanderfolgend im Speicher liegen.
Definition Felder Konstruktor Methoden Beispiel
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

Wenn eine Methode, wie z. B Wenn eine Methode, wie z.B. printGeoForm() für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen wie z.B. Rechtecke oder das andere Mal Kreise auf dem Bildschirm ausgeben bzw. zeichnen kann), dann nennt man dies Polymorphie

Beispiel: In einem Feld sollen verschiedene Objekte (entweder Rechtecke oder Kreise) abgespeichert und dann (z.B. zu Testzwecken) deren spezifischen Daten (Länge und Breite bzw. Radius) ausgegeben werden

Die Reihenfolge der Objekte (Rechteck bzw Die Reihenfolge der Objekte (Rechteck bzw. Kreis) 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 Rechteck und Kreis erzeugen und Objekten der Oberklasse, Objekte der Unterklassen Rechteck oder Kreis zuweisen und die Objekte der Oberklasse im Feld speichern.

Vorgehensweise: Man erzeugt die Klassen Rechteck und Kreis mit jeweils der spezifischen printGeoForm() Methode, die den Flächeninhalt und den Umfang des Rechtecks bzw. des Kreises ausgibt.

Dann erzeugt man eine gemeinsame Basisklasse, z. B Dann erzeugt man eine gemeinsame Basisklasse, z.B. mit dem Namen GeoForm der Klassen Rechteck und Kreis.

In UML-Darstellung:

GeoForm Rechteck Kreis + printGeoForm(): void Rechteck + printGeoForm(): void Kreis + printGeoForm(): void

Mit new werden (in einer Schleife) jeweils ein Rechteck bzw Mit new werden (in einer Schleife) jeweils ein Rechteck bzw. ein Kreis erzeugt und einem Element des Feldes (der Klasse GeoForm) zugewiesen.

GeoForm feld k1 r1 r2 r3 k2 r4 Es werden zufallsbestimmt jeweils entweder die Figuren Kreis oder Rechteck in das Array feld der Klasse GeoForm eingefügt. Der Programmierer will jetzt die Daten der Figuren 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 einen Kreis oder ein Rechteck handelt und dann die entsprechende Methode aufrufen, die die Daten dieser Figur auf dem Bildschirm ausgibt, sondern .... Das Programm weiß von selbst, welche Methode es von welcher Klasse (Rechteck oder Kreis) aufrufen muss!!

Als Programm-Skizze

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

GeoForm[] feld; feld=new GeoForm[3]; ? 0120 0470 null ... null ... Es wird Speicher für eine Referenz (Pointer) auf das Array feld reserviert. feld=new GeoForm[3]; Da feld eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für das Array feld reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Welchen Wert muss feld bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 ? feld[0] 0470 null Auf die (Anfangs)Adresse dieser Speicherbereiche hat der Programmierer keinen Einfluß. Diese legt der Interpreter bzw. Programmlader fest. feld[1] ... null feld[2] ... null

GeoForm[] feld; feld=new GeoForm[3]; 0120 0470 null ... null ... null Es wird Speicher für eine Referenz (Pointer) auf das Array feld reserviert. feld=new GeoForm[3]; Da feld eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für das Array feld reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Welchen Wert muss feld bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 feld[0] 0470 null Auf die (Anfangs)Adresse dieser Speicherbereiche hat der Programmierer keinen Einfluß. Diese legt der Interpreter bzw. Programmlader fest. feld[1] ... null feld[2] ... null

GeoForm[] feld; feld=new GeoForm[3]; 0470 0120 0470 null ... null ... Es wird Speicher für eine Referenz (Pointer) auf das Array feld reserviert. feld=new GeoForm[3]; Da feld eine lokale Variable ist, ist der Wert undefiniert. Es wird Speicher für das Array feld reserviert, das aus lauter Referenzen (Pointern) mit dem vorbelegten Wert null, besteht. Inhalt Adresse Welchen Wert muss feld bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 0470 feld[0] 0470 null Auf die (Anfangs)Adresse dieser Speicherbereiche hat der Programmierer keinen Einfluß. Diese legt der Interpreter bzw. Programmlader fest. feld[1] ... null feld[2] ... null

GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); 0470 2 Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für das Objekt erzeugt, auf das feld [0] zeigen soll. Welchen Inhalt hat diese Adresse und wer legt diesen fest? Es ist der Wert des Radius des neu angelegten Kreises, der durch den Aufruf des Konstruktors festgelegt wird. feld 0120 0470 feld[0] 0470 null feld[1] ... null feld[2] ... null 0700 2

GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); 0470 2 Welchen Wert muss feld[0] bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 0470 feld[0] 0470 null feld[1] ... null feld[2] ... null 0700 2

GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); 0470 2 Welchen Wert muss feld[0] bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 0470 feld[0] 0470 feld[1] ... null feld[2] ... null 0700 2

GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); 0470 2 Welchen Wert muss feld[0] bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 0470 feld[0] 0470 0700 feld[1] ... null feld[2] ... null 0700 2

feld[1] = new Rechteck(10,20); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für das Objekt erzeugt, auf das feld [1] zeigen soll. Welchen Inhalte stehen an dieser Adresse und wer legt diese fest? feld 0120 0470 0800 10 feld[0] 0470 0700 ... 20 feld[1] ... null feld[2] ... null 0700 2

feld[1] = new Rechteck(10,20); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); Es ist der Wert der Breite und Länge des neu angelegten Rechtecks, das durch den Aufruf des Konstruktors festgelegt wird. feld 0120 0470 0800 10 feld[0] 0470 0700 ... 20 feld[1] ... null feld[2] ... null 0700 2

feld[1] = new Rechteck(10,20); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); Welchen Wert muss feld[1] bekommen, damit es auf das gerade angelegte Objekt zeigt? feld 0120 0470 0800 10 feld[0] 0470 0700 ... 20 feld[1] ... null feld[2] ... null 0700 2

feld[1] = new Rechteck(10,20); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); feld 0120 0470 0800 10 feld[0] 0470 0700 ... 20 feld[1] ... feld[2] ... null 0700 2

feld[1] = new Rechteck(10,20); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); feld 0120 0470 0800 10 feld[0] 0470 0700 ... 20 feld[1] ... 0800 feld[2] ... null 0700 2

feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); feld[1].printGeoForm(); Welche printGeoForm() Methode wird nun in feld[0] bzw. feld[1] aufgerufen? Welche 3 Möglichkeiten kann es geben? 1) printGeoForm() in der Klasse GeoForm 2) printGeoForm() in der Klasse Rechteck 3) printGeoForm() in der Klasse Kreis

feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); feld[1].printGeoForm(); Es wird nicht die Methode der Referenzvariablen feld, also printGeoForm() der Klasse GeoForm aufgerufen, sondern die Methode der Klasse des Objekts, auf das die Referenzvariable feld (feld[0], feld[1], ...) zeigt, also hier printGeoForm() der Klasse Rechteck bzw. printGeoForm() der Klasse Kreis.

feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); feld[1].printGeoForm(); Noch genauer: Es wird die Methode des Objekts aufgerufen, die in der Vererbungshierarchie am niedersten ist. Also: Wenn es in der Klasse Rechteck die Methode printGeoForm() gibt, wird diese aufgerufen, sonst die Methode printGeoForm() der Klasse GeoForm. Wenn es in der Klasse Kreis die Methode printGeoForm() gibt, wird diese aufgerufen, sonst die Methode printGeoForm() der Klasse GeoForm.

feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); GeoForm[] feld; feld = new GeoForm[3]; feld[0] = new Kreis(2); feld[1] = new Rechteck(10,20); feld[0].printGeoForm(); feld[1].printGeoForm(); Was macht also: feld[0]. printGeoForm() Radius 2 des Kreises ausgeben. Was macht also: feld[1]. printGeoForm() Breite 10 und Länge 20 des Rechtecks ausgeben.

Das exakte Programm:

public class MainPoly{ public static void main(String[] args){ int i; double zufall; GeoForm[] feld; feld=new GeoForm[3];

for(i=0;i<3;i++){ zufall = Math.random(); if (zufall<0.5){ feld[i] = new Kreis(2); } else{ feld[i] = new Rechteck(10,20); feld[i].printGeoForm();

// Klasse Geometrische Form class GeoForm { public void printGeoForm(){ } Die Methode printGeoForm() wird unbedingt benötigt, auch wenn sie aus keinen Anweisungen besteht. Diese Methode wird ja von den Methoden printGeoForm() der Unterklassen Rechteck und Kreis überschrieben. Die Methode printGeoForm() der Klasse GeoForm kann natürlich auch Anweisungen haben. Ebenso kann die Klasse GeoForm auch Attribute und weitere Methoden besitzen. Auf diese Methoden in GeoForm kann in den Unterklassen auch zugegriffen werden, wie z.B: mit super. printGeoForm() oder mit super(...) in einem Konstruktor einer Unterklasse.

class Rechteck extends GeoForm{ private double l; private double b; public Rechteck(double pl, double pb){ setLaenge(pl); setBreite(pb); } public void setLaenge( double pl){ l = pl;

public void setBreite( double pb){ b = pb; } public double getLaenge(){ return(l); public double getBreite(){ return(b);

public void printGeoForm(){ System.out.print("Zeichnet Rechteck mit: "); System.out.print("Laenge= "+getLaenge()); System.out.println(" und Breite= "+getBreite()); }

class Kreis extends GeoForm{ private double r; public Kreis(double pr){ setRadius(pr); } public void setRadius( double pr){ r = pr; public double getRadius(){ return(r);

public void printGeoForm(){ System.out.println("Zeichnet Kreis mit Radius=" +getRadius()); }

Die Dreischichten-Architektur verlangt, dass die Fachklassen "stumm" sind. Nur die Klassen, die sich mit der Oberfläche beschäftigen, sollen die Eingabe und Ausgabe bewerkstelligen.

Welche Methode verletzt die Dreischichten-Architektur ? printGeoForm()

Diese Methode bringt einen Text auf den Bildschirm Diese Methode bringt einen Text auf den Bildschirm. Sie soll aber keinen Text auf den Bildschirm bringen. Das soll in der Klasse geschehen, wo sich die Methode main(...) befindet.

Die Methode printGeoForm soll den Text als Zeichenkette über einen output-Parameter zurückgeben. Entweder über return, oder über einen Parameter in printGeoForm(...)

Aufgabe: Schreiben Sie ein Java-Programm, in dem die Methode printGeoForm den Text als Zeichenkette über einen output-Parameter zurückgibt. Entweder über return, oder über einen Parameter in printGeoForm(...). In main(...) soll dann der Text mit System.out.println(...) auf dem Bildschirm ausgegeben werden. Verwenden Sie dazu die entsprechenden Methoden der Klasse String, bzw. StringBuffer.

Bemerkung: In den folgenden Lösung sind die wesentlichen Teile (d.h. die Teile des Programms, die sich vom vorhergehenden unterscheiden), rot markiert.

Lösung mit return:

public class MainPoly3 { public static void main(String[] args){ int i; double zufall; String str; GeoForm[] feld; feld=new GeoForm[3]; for(i=0;i<3;i++){ zufall = Math.random(); if (zufall<0.5){ feld[i] = new Kreis(2); }

str=feld[i].getGezGF(); System.out.println(str); else{ feld[i] = new Rechteck(10,20); } for(i=0;i<3;i++){ str=feld[i].getGezGF(); System.out.println(str); Abkürzung für: getGezeichnetGeoForm

class GeoForm { public String getGezGF(){ return(null); }

class Rechteck extends GeoForm{ private double laenge; private double breite; public Rechteck(double plaenge, double pbreite){ setLaenge(plaenge); setBreite(pbreite); } public void setLaenge(double plaenge){ laenge = plaenge; }

public void setBreite(double pbreite){ breite = pbreite; } public double getLaenge(){ return(laenge); public double getBreite(){ return(breite);

public String getGezGF(){ String str1, str2, str3; str1="Rechteck mit Laenge= "+Double.toString(getLaenge()); str2=" und Breite= "+Double.toString(getBreite()); str3=str1+str2; return(str3); }

class Kreis extends GeoForm{ private double radius; public Kreis(double pradius){ setRadius(pradius); } public void setRadius(double pradius){ radius = pradius;

public double getRadius(){ return(radius); } public String getGezGF(){ String str; str="Kreis mit Radius= "+Double.toString(getRadius()); return(str);

Lösung mit Parameter:

public class MainPoly4 { public static void main(String[] args){ int i; double zufall; StringBuffer myStringbuf = new StringBuffer(); GeoForm[] feld; feld=new GeoForm[3]; for(i=0;i<3;i++){ zufall = Math.random(); if (zufall<0.5){ feld[i] = new Kreis(2); }

else{ feld[i] = new Rechteck(10,20); } for(i=0;i<3;i++){ feld[i].getGezGF( myStringbuf); System.out.println( myStringbuf.toString());

class GeoForm { public void getGezGF(StringBuffer ps){ }

class Rechteck extends GeoForm{ private double laenge; private double breite; public Rechteck(double plaenge, double pbreite){ setLaenge(plaenge); setBreite(pbreite); } public void setLaenge(double plaenge){ laenge = plaenge;

public void setBreite(double pbreite){ breite = pbreite; } public double getLaenge(){ return(laenge); public double getBreite(){ return(breite);

public void getGezGF( StringBuffer ps){ StringBuffer buf; String str1, str2, str3, str4; ps.setLength(0); str1="Rechteck mit Laenge= "+Double.toString(getLaenge()); str2=" und Breite= "+Double.toString(getBreite()); str3=str1+str2; buf=new StringBuffer(str3); ps.append(buf); }

class Kreis extends GeoForm{ private double radius; public Kreis(double pradius){ setRadius(pradius); } public void setRadius(double pradius){ radius = pradius; public double getRadius(){ return(radius);

public void getGezGF( StringBuffer ps){ StringBuffer buf; String str; ps.setLength(0); str="Kreis mit Radius= "+Double.toString(getRadius()); buf= new StringBuffer(str); ps.append(buf); }