From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100055.html | 447 +++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100055.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100055.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100055.html b/Master/Reference Architectures and Patterns/hjp5/html/k100055.html new file mode 100644 index 0000000..1043fa0 --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100055.html @@ -0,0 +1,447 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 8 - OOP II: Vererbung, Polymorphismus und statische Elemente +
+
+ + + + +

8.4 Abstrakte Klassen und Polymorphismus

+
+ +
+ + + + +

8.4.1 Abstrakte Klassen

+ +

+In Java ist es möglich, abstrakte Methoden zu definieren. +Im Gegensatz zu den konkreten Methoden enthalten sie nur die +Deklaration der Methode, nicht aber ihre Implementierung. Syntaktisch +unterscheiden sich abstrakte Methoden dadurch, dass anstelle der geschweiften +Klammern mit den auszuführenden Anweisungen lediglich ein Semikolon +steht. Zusätzlich wird die Methode mit dem Attribut abstract +versehen. Abstrakte Methoden können nicht aufgerufen werden, +sie definieren nur eine Schnittstelle. Erst durch Überlagerung +in einer abgeleiteten Klasse und Implementierung des fehlenden Methodenrumpfes +wird eine abstrakte Klasse konkret und kann aufgerufen werden. + +

+

+ + + + + + + + + +
+ +

+Eine Klasse, die mindestens eine abstrakte Methode enthält, wird +selbst als abstrakt angesehen und muss ebenfalls mit dem Schlüsselwort +abstract +versehen werden. Abstrakte Klassen können nicht instanziert werden, +da sie Methoden enthalten, die nicht implementiert wurden. Statt dessen +werden abstrakte Klassen abgeleitet, und in der abgeleiteten Klasse +werden eine oder mehrere der abstrakten Methoden implementiert. Eine +abstrakte Klasse wird konkret, wenn alle ihre Methoden implementiert +sind. Die Konkretisierung kann dabei auch schrittweise über mehrere +Vererbungsstufen erfolgen.

+ + + + +
 Hinweis 
+
+ + + + +

8.4.2 Ein Beispiel für Polymorphismus

+ +

+Wir wollen uns ein Beispiel ansehen, um diese Ausführungen zu +verdeutlichen. Zum Aufbau einer Mitarbeiterdatenbank soll zunächst +eine Basisklasse definiert werden, die jene Eigenschaften implementiert, +die auf alle Mitarbeiter zutreffen, wie beispielsweise persönliche +Daten oder der Eintrittstermin in das Unternehmen. Gleichzeitig +soll diese Klasse als Basis für spezialisierte Unterklassen verwendet +werden, um die Besonderheiten spezieller Mitarbeitertypen, wie Arbeiter, +Angestellte oder Manager, abzubilden. Da die Berechnung +des monatlichen Gehalts zwar für jeden Mitarbeiter erforderlich, +in ihrer konkreten Realisierung aber abhängig vom Typ des Mitarbeiters +ist, soll eine abstrakte Methode monatsBrutto +in der Basisklasse definiert und in den abgeleiteten Klassen konkretisiert +werden. + +

+Das folgende Listing zeigt die Implementierung der Klassen Mitarbeiter, +Arbeiter, Angestellter +und Manager zur Realisierung +der verschiedenen Mitarbeitertypen. Zusätzlich wird die Klasse +Gehaltsberechnung definiert, +um das Hauptprogramm zur Verfügung zu stellen, in dem die Gehaltsberechnung +durchgeführt wird. Dazu wird ein Array ma +mit konkreten Untertypen der Klasse Mitarbeiter +gefüllt (hier nur angedeutet; die Daten könnten zum Beispiel +aus einer Datenbank gelesen werden) und dann für alle Elemente +das Monatsgehalt durch Aufruf von monatsBrutto +ermittelt. +

+ + + + + + + + + +
+ +

+Das Listing ist ebenfalls ein Beispiel für Polymorphismus. +Eine Variable vom Typ einer Basisklasse nimmt zur Laufzeit unterschiedliche +Objekte aus abgeleiteten Klassen auf. Da bereits in der Basisklasse +die Definition von monatsBrutto +vorgenommen wurde, akzeptiert der Compiler den Aufruf dieser Methode +bereits bei Objekten dieser vermeintlich abstrakten Klasse. Erst zur +Laufzeit ist dann bekannt, welcher abgeleitete Typ hinter jedem einzelnen +Array-Element steht, und das Laufzeitsystem ruft die darin implementierte +Variante der Methode monatsBrutto +auf.

+ + + + +
 Hinweis 
+
+ + +

+ + + + + +
+ +
+001 /* Gehaltsberechnung.java */
+002 
+003 import java.util.Date;
+004 
+005 abstract class Mitarbeiter
+006 {
+007   int persnr;
+008   String name;
+009   Date eintritt;
+010 
+011   public Mitarbeiter()
+012   {
+013   }
+014 
+015   public abstract double monatsBrutto();
+016 }
+017 
+018 class Arbeiter
+019 extends Mitarbeiter
+020 {
+021   double stundenlohn;
+022   double anzahlstunden;
+023   double ueberstundenzuschlag;
+024   double anzahlueberstunden;
+025   double schichtzulage;
+026 
+027   public double monatsBrutto()
+028   {
+029     return stundenlohn*anzahlstunden+
+030            ueberstundenzuschlag*anzahlueberstunden+
+031            schichtzulage;
+032   }
+033 }
+034 
+035 class Angestellter
+036 extends Mitarbeiter
+037 {
+038   double grundgehalt;
+039   double ortszuschlag;
+040   double zulage;
+041 
+042   public double monatsBrutto()
+043   {
+044     return grundgehalt+
+045            ortszuschlag+
+046            zulage;
+047   }
+048 }
+049 
+050 class Manager
+051 extends Mitarbeiter
+052 {
+053   double fixgehalt;
+054   double provision1;
+055   double provision2;
+056   double umsatz1;
+057   double umsatz2;
+058 
+059   public double monatsBrutto()
+060   {
+061     return fixgehalt+
+062            umsatz1*provision1/100+
+063            umsatz2*provision2/100;
+064   }
+065 }
+066 
+067 public class Gehaltsberechnung
+068 {
+069   private static final int ANZ_MA = 100;
+070   private static Mitarbeiter[] ma;
+071   private static double bruttosumme;
+072 
+073   public static void main(String[] args)
+074   {
+075     ma = new Mitarbeiter[ANZ_MA];
+076 
+077     //Mitarbeiter-Array füllen, z.B.
+078     //ma[0] = new Manager();
+079     //ma[1] = new Arbeiter();
+080     //ma[2] = new Angestellter();
+081     //...
+082 
+083     //Bruttosumme berechnen
+084     bruttosumme = 0.0;
+085     for (int i=0; i<ma.length; ++i) {
+086       bruttosumme += ma[i].monatsBrutto();
+087     }
+088     System.out.println("Bruttosumme = "+bruttosumme);
+089   }
+090 }
+
+
+Gehaltsberechnung.java
+ +Listing 8.11: Abstrakte Klassen und Methoden

+ +

+Unabhängig davon, ob in einem Array-Element ein Arbeiter, Angestellter +oder Manager gespeichert wird, führt der Aufruf von monatsBrutto +dank der dynamischen Methodensuche die zum Typ des konkreten Objekts +passende Berechnung aus. Auch weitere Verfeinerungen der Klassenhierarchie +durch Ableiten neuer Klassen erfordern keine Veränderung in der +Routine zur Berechnung der monatlichen Bruttosumme. + +

+So könnte beispielsweise eine neue Klasse GFManager +(ein Manager, der Mitglied der Geschäftsführung ist) aus +Manager abgeleitet und problemlos in die Gehaltsberechnung integriert +werden: + + +

+ + + + +
+ +
+001 public class GFManager
+002 extends Manager
+003 {
+004   double gfzulage;
+005 
+006   public double monatsBrutto()
+007   {
+008     return super.monatsBrutto()+gfzulage;
+009   }
+010 }
+
+
+ +Listing 8.12: Einfügen einer neuen Mitarbeiterklasse in die Gehaltsberechnung

+

+ + + + + + + + + +
+ +

+In der abgedruckten Form ist das Programm in Listing 8.11 +natürlich nicht lauffähig, denn das Array ma +wird nicht vollständig initialisiert. Ansonsten ist es aber korrekt +und illustriert beispielhaft die Anwendung abstrakter Klassen und +Methoden.

+ + + + +
 Hinweis 
+
+ + + + +

8.4.3 Polymorphe Methodenaufrufe in Konstruktoren

+ +

+Eine besondere Gefahrenquelle liegt darin, polymorphe Methoden im +Konstruktor einer Klasse aufzurufen. Der Grund liegt in der Initialisierungsreihenfolge +von Membervariablen während der Konstruktion eines Objekts: +

+ +

+Wird nun im eigenen Konstruktor eine Methode aufgerufen, die in einer +abgeleiteten Klasse überlagert wurde, sind die Membervariablen +der abgeleiteten Klasse noch nicht initialisiert. Ihr Konstruktor +wird ja erst später aufgerufen. Das folgende Beispiel illustriert +dieses Problem: + + +

+ + + + + +
+ +
+001 /* Listing0813.java */
+002 
+003 class SingleValue
+004 {
+005   protected int value1;
+006 
+007   public SingleValue(int value1)
+008   {
+009     this.value1 = value1;
+010     print();
+011   }
+012 
+013   public void print()
+014   {
+015     System.out.println("value = " + value1);
+016   }
+017 }
+018 
+019 class ValuePair
+020 extends SingleValue
+021 {
+022   protected int value2;
+023 
+024   public ValuePair(int value1, int value2)
+025   {
+026     super(value1);
+027     this.value2 = value2;
+028   }
+029 
+030   public void print()
+031   {
+032     System.out.println(
+033       "value = (" + value1 + "," + value2 + ")"
+034     );
+035   }
+036 }
+037 
+038 public class Listing0813
+039 {
+040   public static void main(String[] args)
+041   {
+042     new ValuePair(10,20);
+043   }
+044 }
+
+
+Listing0813.java
+ +Listing 8.13: Polymorphe Methodenaufrufe im Konstruktor

+ +

+Die Ausgabe des Programms ist nicht »value = 10«, sondern +»value = (10,0)«. Bei der Konstruktion des ValuePair-Objekts +wird zunächst der Konstruktor der Basisklasse SingleValue +aufgerufen und initialisiert seine Membervariable value1. +Der anschließende Aufruf von print +wird polymorph ausgeführt, denn das zu instanzierende Objekt +ist vom Typ ValuePair. Da zu +diesem Zeitpunkt der Member value2 +aber noch nicht initialisiert ist (das würde erst passieren, +wenn der Konstruktor von SingleValue +komplett abgearbeitet wäre), wird an seiner Stelle 0 ausgegeben +(beim Anlegen eines neuen Objekts wird der belegte Speicher mit Nullen +gefüllt). Das kann zu schwer auffindbaren Fehlern führen. +Aufrufe von Methoden, die möglicherweise überlagert werden, +sollten daher im Konstruktor vermieden werden. +


+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3