8. Vererbung
8. VererbungVererbung ist ein wichtiger Bestandteil der objektorientierten Programmierung. Vererbung ergänzt die bisher vorgestellten Konzepte der
- Aggregation (Klassen, Felder, Datenstrukturen)
- Assoziation (Referenzen)
um ein weiteres Strukturierungsmittel.
Der erste Abschnitt beschäftigt sich mit dern Konzepten der Vererbung, die folgenden beschreiben die Implementierung in Java.
- 9605 views
8.1 Das Konzept der Vererbung
8.1 Das Konzept der VererbungDie Ziele die mit Vererbung in der objektorientierten Programmierung verfolgt werden sind:
- Wiederverwendung
- eine Klasse vererbt Eigenschaften an eine andere.
- Dies bedeutet: Man nutzt Daten und Methoden einer Klasse
- Modellierung in Hierarchien
- Hierarchien sind gängige Konzepte des Alltagsleben und finden sich in der Begrifflichkeit des Alltagslebens wieder. Eine Modellierung die Hierarchien unterstützt und vereinfacht das Verständnis und die Kommunikation.
- Hierarchien sind Konzepte die stark bei der Abgrenzung zwischen ähnlichen Dingen helfen
Beispiel einer Vererbungshierarchie: |
Die gleiche Begriffshierarchie lässt sich auch als Mengendiagramm darstellen: |
Alle Mitglieder einer Teilmenge haben die gleichen Eigenschaften.
Das Mengendiagramm verdeutlicht, dass es sich bei der Vererbungshierarchie um eine "Ist-ein" Relation handelt.
Vererbung und Klassen
Die Konzepte der Vererbungshierarchien lässt sich leicht auf Klassen abbilden
Das Diagramm rechts verdeutlicht die Beziehungen zwischen den Klassen, ihrer Bedeutung und der Typisierung. |
Ein- und Mehrfachvererbung
Programmiersprachen wie C++ erlauben die Benutzung von Mehrfachvererbung. Die Sprache Java erlaubt jedoch nur eine einfache Vererbung.
- Einfachvererbung: Eine Unterklasse erbt von genau einer Oberklasse
- Mehrfachvererbung: Eine Unterklasse erbt von mehreren Oberklassen
Das Konzept der Mehrfachvererbung durchbricht zu einem gewissen Grad das Konzept der Spezialisierung-Generalisierung. Bei der Einfachvererbung sind Personen Mitarbeiter oder Berater aber nicht beides gleichzeitig. Bei der Mehrfachvererbung mit einer einzelnen Basisklasse werden Unterklassen zuerst als disjunkte Klassen definiert. Später sollen Unter-Unterklassen jedoch die gleichen Eigenschaften über verschieden Vererbungspfade erben.
Anmerkung
Mehrfachvererbung erhöht die Mächtigkeit sowie die Komplexität einer Sprache erheblich. Es kann hier leicht zu Effekten kommen die ein Entwickler nicht als intuitiv empfindet. Das Risiko des Fehlverhaltens einer Anwendung steigt hierdurch.
Beim Entwurf der Sprache Java wurde bewusst auf Mehrfachvererbung verzichtet um die Sprache einfach zu halten und um die Implementierung eines effizienten Laufzeitsystems zu vereinfachen.
Die Java Interface (Schnittstellen) Technologie bietet eine "Hintertür" zur Implementierung von Fällen in denen eine Mehrfachvererbung wünschenswert ist.
- 11472 views
8.2 Vererbung in Java
8.2 Vererbung in JavaDie Vererbungsbeziehung wird in Java mit dem Schlüsselwort extends beschrieben. Beispiel:
class Mitarbeiter extends Person { /* Klassenimplementierung */ }
Die Klasse Mitarbeiter ist eine Spezialisierung der Klasse Person. Sie erbt die öffentlichen Attribute und Methoden der Klasse Person.
Alle Klassen in Java erben direkt oder indirekt von der Java Basisklasse Object. Wird bei einer Klassendeklaration keine extends Klausel angegeben so wird die Klasse automatisch von der Klasse Object abgeleitet.
Die Klasse Object
... stellt für alle Javaklassen eine minimale Infrastruktur zur Verfügung:
- die Möglichkeit dynamisch Objekte auf dem Heap anzulegen
- eine Identität und die damit verbundene Möglichkeit zum Vergleich von Objekten
- die Möglichkeit des automatischen Löschens wenn keine Referenz mehr auf eine Instanz zeigt.
- Möglichkeit der Instrospektion (Dynamisches Erkunden der Struktur der Klasse)
Zugriff auf geerbte Methoden und Attribute
Oberklassen vererben öffentliche (public, protected) Methoden und Attribute an Unterklassen. Das heißt, dass sie wie eigene Attribute verwendet werden können.
Die Beispielklasse Person verfügt über:
- private Attribute für Vor- und Nachnamen
- öffentliche Methode zum Auslesen des Gesamtnamens
- öffentliche Methode zum Setzen des Namens
- ein öffentliches Attribut zum Verwalten des Alters
- Einen Konstruktor zum Setzen des Namens
Die Oberklasse Person
package s1.block8; public class Person { private String name; private String firstName; public int age; public Person(String ln, String fn) { name = ln; firstName = fn; } public Person() { this("Doe","John");} public void setName(String ln, String fn) { name = ln; firstName = fn; } public String fullName() {return (name + " " + firstName);} }
Die Klasse Employee soll jetzt die öffentlichen Eigenschaften der Oberklasse Person nutzen. So kann eine redundante Programmierung der schon existierenden Funktionalität vermieden werden.
Die Unterklasse Employee
package s1.block8; public class Employee extends Person { private String employeeId; public Employee(String ln, String fn, String EmpId, int a) { super(ln,fn); // Java ruft hier den Konstruktor der Oberklasse auf employeeId = EmpId; age = a; } public String getEmployeeId() {return employeeId;} public String printAll() { return ( fullName() + " " + employeeId + " " + age); } public static void main(String[] args) {
Employee ceo = new Employee("Doe","Jane", "1", 25);
Employee cto = new Employee("Miller","John","2", 30);cto.age++;
System.out.println(ceo.printAll());
System.out.println(cto.printAll());
} }
Benutzung der Klasse
Die so implementierte Klasse kann wie folgt verwendet werden:
Doe Jane 1 25 Miller John 2 31
Alle öffentlichen Attribute und Methoden (Beispiel age) der Klasse Person können in der Klasse Employee genutzt werden als ob es eigene/lokale sind.
Die Vererbung funktioniert jedoch nicht rückwärts. Man kann einer Instanz von Person keine Angestelltennummer (employeeId) zuweisen. Sie existiert in der Klasse Person nicht.
"Vertragsrecht": Alle Instanzen von Employee müssen sich auch genau wie Instanzen von Person verhalten. Sie sind auch Instanzen der Klasse Person. Andere Konsumenten im Programm verlassen sich auf dieses Verhalten, diesen "Vertrag". Dies bedeutet:
- Die Unterklasse muss eventuell erzwungene Intialisierungen der Oberklasse achten in dem Sie rekursiv deren Konstruktoren aufruft.
- Veröffentlichte Attribute und Methoden können/sollen nicht mehr blockiert werden. Beispiel: In einem Unternehmen darf das Alter aufgrund von rechtlichen Bestimmungen nicht veröffentlicht werden
Vererbung in UML
Implementierung ohne Vererbung | Implementierung mit Vererbung |
---|---|
Hier eine Implementierung der Klasse Employee ohne Vererbung. Die Implementierung entspricht der rechten Implementierung mit Vererbung. Die Methoden der Klasse haben hier aber direkten Zugriff auf die privaten Attribute name, firstName. |
Eine Implementierung der Klasse Employee mit Vererbung der Klasse Person Vererbung |
Vererbung privater Attribute und Methoden
Private Attribute werden nicht vererbt!
Sie sind nur innerhalb der Klasse sichtbar. Eine Unterklasse hat keinen priviligierten Zugriff auf private Methoden. Sie werden nicht vererbt. Eine Unterklasse muss wie jede andere Klasse über vorhandene öffentliche Zugriffsmethoden auf die privaten Attribute zugreifen.
Vererbung und Konstruktoren
Konstruktoren werden in Java nicht vererbt. Man Sie nur indirekt über den new() Operator für eine gegebene Klasse aufrufen.
Konstruktoren müssen für jede Unterklasse implementiert werden. Die Konstruktoren der Unterklasse müssen jedoch in der Lage sein existierende Konstruktoren der Oberklasse aufzurufen, da sie für die Initialisierung der Oberklasse notwendig sind. Hierzu wird das Schlüsselwort super() verwendet.
Hiermit kann man jetzt die Klasse Employee() eleganter und robuster Initialisieren
public class Employee extends Person { private String employeeId; public Employee(String ln, String fn, String EmpId, int a) { super(fn,ln); // Java ruft hier den Konstruktor der Oberklasse auf employeeId = EmpId; age = a; } public void printAll() { System.out.println ( fullName() + " " + employeeId + " " + age); }
Wichtig: Der Aufruf des Konstruktors der Oberklasse muss als erster Befehl im Konstruktor der Unterklasse stehen. Die Attribute der Oberklasse müssen als erstes initialisiert werden, bevor die Attribute der Unterklasse initialisiert werden. Nur so kann gewährleistet werden dass sich Instanzen der Oberklasse korrekt verhalten. Würde der Aufruf des Konstruktors der Oberklasse nicht als erstes geschehen, könnte die Unterklasse die Oberklasse inkorrekt manipulieren.
Unterklassenkonstruktoren ohne super() Aufruf
Konstruktoren müssen nicht einen bestimmten Konstruktor der Oberklasse explizit aufrufen.
Wird kein super() Aufruf implementiert, so generiert der Übersetzer automatisch einen super() Aufruf der den Standard(default)konstruktor aufruft.
Hiermit wird immer ein vollständiges Durchlaufen der Klassenhierachie beim Initialisieren gewährleistet.
Besitzt die Oberklasse nur Konstruktoren mit Übergabeparameter so muss einer dieser Konstruktoren über super() aufgerufen werden.
Im folgenden Beispiel kann man die Initialisierungskette einer Klasse C sehen die aus B abgeleitet wird. B wird aus A abgeleitet:
public class A { public A() {System.out.println("Constructor A called");} } public class B extends A{ public B() {System.out.println("Constructor B called");} } public class C extends B { public C() {System.out.println("Constructor C called");} }
Das erzeugen einer Instanz von C:
C c = new C();
Triggert die folgenden Ausgaben:
Constructor A called Constructor B called Constructor C called
- 148070 views
8.3 Überschreiben (Overriding)
8.3 Überschreiben (Overriding)Das im vorgehenden Abschnitt vorgestellte Konzept des Vererbens ging immer von einer Erweiterung der Klasse aus. Das heißt mehr und mehr Attribute und Methoden kommen hinzu.
Es kommt jedoch vor, das eine spezialisierte Klasse eine existierende Methode der Oberklasse "verfeinern" möchte. Dieses Konzept der Implementierung einer Methode oder Attributs welches eine Methode oder Attribut aus der Oberklasse neu implementiert, wird in der objektorientierten Programmierung Überschreiben (Overriding) genannt.
Überschreiben von Methoden
Java erlaubt die Methode einer Oberklasse zu überschreiben, das bedeutet sie zu verdecken, wenn die folgenden Bedingungen für die Deklaration der Methode erfüllt sind
- Namensgleicher Methodenname
- Eingabeparameter sind von Anzahl, Reihenfolge und Typ identisch
- Rückgabeparameter ist identisch
- Zugriffsrechte der Methode der Oberklasse (public, protected, private) werden nicht eingeschränkt
Der Methodenrumpf kann mit einer beliebigen Implementierung ausgeführt werden. Mit dieser Technik kann eine Unterklasse eine eigene Implementierung für eine allgemeinere Methode einer Überklasse zur Verfügung stellen.
Im vorhergehenden Fall der Klasse Employee kann man eine spezialisierte Klasse Manager implementieren, die ein zusätzliches Budget verwalten kann. Das Budget soll ebenfalls mit der Methode printAll() ausgeben werden.
package s1.block8; public class Manager extends Employee { public int budget; public Manager(String ln, String fn, String EmpId, int a, int b) { super(ln, fn,EmpId,a); budget = b; } public String printAll() { return ( fullName() + " " + getEmployeeId() + " " + age + " " + budget); } public static void main(String[] args) {
Employee ceo = new Employee("Doe","Jane", "1", 25); Employee cto = new Employee("Miller","John","2", 30); Employee man1 = new Manager("Johnson","Susan","3", 29, 30000); cto.age++; System.out.println(ceo.printAll()); System.out.println(cto.printAll()); System.out.println(man1.printAll());; } }
...erzeugt die folgenden Ausgaben:
Doe Jane 1 25 Miller John 2 31 Johnson Susan 3 29 30000
Überschriebene Methoden sind miteinander verwandt und eine Benutzung der Methode der Oberklasse ist gewünscht um Codereplikation und Redundanz zu vermeiden. Hierfür existiert das Schlüsselwort super. Es erlaubt das Aufrufen der überschriebenen Methode mit der folgenden Syntax:
super.MethodenName(para_1, ..,para_n)
Im Fall der Klasse Manager kann man die printAll() Methode mit dem Schlüsselwort super vereinfachen:
public class Manager extends Employee { public int budget; public Manager(String ln, String fn, String EmpId, int a, int b) { super(ln, fn,EmpId,a); budget = b; } public String printAll() { return super.printAll() + " " + budget; } }
Hinweis: Die Syntax super.super.methodenname() ist nicht möglich. Man kann nicht die Methode einer Ober-Oberklasse unter Auslassung der Oberklasse aufrufen.
Suchalgorithmus der Laufzeitumgebung
Da in Java alle Klassen einzeln übersetzt werden können, kann man erst zur Laufzeit entscheiden welche Methode aufgerufen werden muss (dynamic invocation). Die Laufzeitumgebung geht bei jedem Aufruf wie folgt vor
- Bestimme Typ des Objekts
- Versuche Methode zum passenden Typ (Klasse) auszuführen
- Versuche rekursiv in der Oberklasse die Methode auszuführen
Überschreiben von Attributen
Für das Überschreiben von Attributen gelten die gleichen Regeln wie für das Überschreiben von Methoden:
- Namensgleicher Attributname
- Zugriffsrechte des Attributs der Oberklasse (public, protected) werden nicht eingeschränkt
Private Attribute werden nicht vererbt. Sie sind der Unterklasse weder bekannt noch zugänglich!
Der Zugriff auf ein überschriebenes Attribut der Oberklasse geht symmetrisch zu den Methoden mit dem super Schlüsselwort. Beispiel:
a = super.a * 2;
Die @Override Annotation
Java kennt seit JDK 1.5 Annotationen. Annotationen sind Hinweise für den Übersetzer.
Es ist guter Stil wenn man einer Methode die Überschrieben wird die Annotation
@Override
voranstellt. @Overriding ist eine fest eingebaute Annotation, die den Übersetzer zu einer Fehlermeldung zwingt wenn die aufgewählte Methode nicht die Methode der Oberklasse überschreibt (Siehe Oracle Tutorial Annotationen).
Javaentwicklungsumgebungen tendieren eine Warnung zu erzeugen, falls eine überschriebene Methode nicht mit dieser Annotation erzeugt wurde.
- 51658 views
"In vielen Fällen sind
"In vielen Fällen sind überladene Methoden miteinander verwandt und eine Benutzung der Methode der Oberklasse ist gewünscht um Codereplikation und Redundanz zu vermeiden."
Das sollte doch bestimmt überschriebene statt überladene heißen? :)
- Log in to post comments
Aua, stimmt.
Da habe ich mir selbst ein Bein gestellt. Fehler wurde korrigiert. Der Satz wurde auch leicht verändert.
- Log in to post comments
8.4 Abstrakte und finale Klassen
8.4 Abstrakte und finale KlassenFinale Klassen und Methoden
Java bietet die Möglichkeit Klassen und Methoden zu implementieren die nicht mehr abgeleitet oder überschrieben werden dürfen. Hierzu dient das Schlüsselwort final.
Finale Methoden
Mit dem Schlüsselwort final kann man das Überschreiben der Methode in einer Unterklasse unterbinden. Ein typsiches Beispiel hierfür ist:
public final void print() { /* Methodenrumpf */}
Unterklassen mit überschriebenen Methoden sind ein sehr mächtiges Konzept für den Entwickler einer Unterklasse. Eine Unterklasse kann inhaltlich eine Oberklasse in weiten Bereichen neu implementieren, solange die Signaturen der Methoden gewahrt bleiben und ein Konstruktor der Oberklasse benutzt. Die Kontrolle liegt fast vollständig in den Händen der Unterklasse. das Schlüsselwort final erlaubt dem Entwickler der Oberklasse
- das Überschreiben zu verbieten
- und damit die Sichtbarkeit der Methode der Oberklasse für beliebige Konsumenten der Unterklasse zu garantieren
Dem Entwickler der Unterklasse steht es nach wie vor frei Methoden mit anderen Signaturen zu verwenden.
Finale Klassen
Finale Klassen verbieten die Spezialisierung einer Klasse durch eine Unterklasse.
Das Schlüsselwort final kommt im folgenden Beispiel zum Einsatz:
final class chiefExecutiveOfficer extends Manager { /* Klassen Implementierung */}
Beispiel
- Systemklasse String: Die Klasse String ist final, da Zeichenketten hochoptimiert und nicht veränderbar sind. Das Javalaufzeitsystem verwendet spezielle Optimierungen wie Stringpools und es nutzt die Unveränderbarkeit von Zeichenketten um dem Anwender Zugriff auf spezielle Zeichenketten des Laufzeitsystems zu geben. Die Möglichkeit diese Klasse zu spezialisieren wurde unterbunden um Sicherheit und Leistung zu garantieren.
Abstrakte Klassen und Methoden
Abstrakte Klassen
Abstrakte Klassen und Java-Schnittstellen (Stoff des zweiten Semester) dienen in Java zur Modularisierung und damit oft zur Arbeitsteilung zwischen Entwicklern. Abstrakte Klassen erlauben es dem Entwickler eine Oberklasse zu implementieren die nicht selbst instanziiert werden darf. Dieses Konzept erlaubt es Klassen als Vorlagen zu implementieren und gleichzeitig zu erzwingen, dass die Entwickler der Unterklasse fehlende oder eigene Methoden und Attribute zur Verfügung stellen. Hiermit lassen sich allgemeine Konzepte implementieren die zu allgemein sind um Instanziierungen zu erlauben, Dies erfolgt mit dem Schlüsselwort abstract bei der Spezifikation der Klasse.
Die Klasse Person im vorhergehenden Beispiel ist eine Klasse von der man nicht erlauben möchte, dass sie instanziiert wird. Dies geschieht zum Beispiel so:
public abstract class Person { private String name; private String firstName; public int age; public Person(String ln, String fn) { name = ln; firstName = fn; } public Person() { this("Doe","John");} public void setName(String ln, String fn) { name = ln; firstName = fn; } public String fullName() {return (name + " " + firstName);} }
Versucht man nun eine Person zu instanziieren:
Person p1 = new Person("persona","nongrata");
...führt dies beim Übersetzen zu folgendem Fehler:
javac Main.java Main.java:8: Person is abstract; cannot be instantiated Person p1 = new Person("persona","nongrata"); ^ 1 error
Abstrakte Klassen haben die typischen Eigenschaften von normalen Javaklassen. Sie haben Attribute und Methoden die vererbt werden können.
Wichtige Eigenschaften abstrakter Klassen |
---|
|
Beispiel
Die Systemklasse Number: Die Klasse Number enthält gemeinsame Methoden für zahlenartige Typen. Man kann sie jedoch nicht direkt instanziieren. Die daraus abgeleiteten Klassen Byte, Float etc. sind final. Sie sind hochoptimiert und sollen aus Performance- und Sicherheitsgründen nicht spezialisiert werden.
Abstrakte Methoden
Normale Methoden und Attribute werden an die Unterklasse vererbt und können auch bei Bedarf überschrieben werden.
Wird jedoch eine Methode mit dem Schlüsselwort abstract gekennzeichnet so muss sie von einer nicht abstrakten Unterklasse implementiert und überschrieben werden.
Beispiel
Die Klasse Person kann so erzwingen, dass eine printAll() Methode für alle Unterklassen implementiert muss, ohne sie selbst zu implementieren.
public abstract class Person { private String name; private String firstName; public int age; public Person(String ln, String fn) { name = ln; firstName = fn; } public Person() { this("Doe","John");} public void setName(String ln, String fn) { name = ln; firstName = fn; } public String fullName() {return (name + " " + firstName);} public abstract String printAll(); }
Regel: Eine Unterklasse einer abstrakten Klasse muss:
- alle abstrakten Methoden implementieren um nicht "abstrakt" zu sein
oder
- selbst eine abstrakte Klasse sein, falls sie nicht alle oder keine der abstrakten Methoden implementiert.
- 30226 views
Wort fehlt
Bei dem ersten Satz nach der Überschrift „Finale Methoden“ fehlt das Verb „kann“.
- Log in to post comments
8.5 Entwurfsüberlegungen zur Vererbung
8.5 Entwurfsüberlegungen zur VererbungDie Möglichkeiten der Vererbung sind sehr ausdrucksstark, haben viele Vorteile, bergen aber auch Risiken. Hierbei muss man mindestens drei verschieden Entwicklerrollen beachten:
- Implementierer der Oberklasse
- entwirft ein semantisches Konzept für eine Klassenhierarchie
- implementiert allgemeingültige Methoden und Attribute
- gibt Rahmenwerk durch Zugriffsmethoden, Zugriffskontrolle, explizite Möglichkeit zum Vererben und Überschreiben vor
- Implementierer der Unterklasse
- nutzt Infrastruktur
- muss sich an Syntax und Zugriffskontrollen halten
- macht Annahmen über Semantik der Oberklasse
- verfeinert und verändert Funktionalität
- Benutzer der Klassenhierarchie
- macht Annahmen zur gesamten Klassenhierarchie
- nutzt Syntax
- erschliesst Semantik aus Klassendeklaration, Dokumentation und experimenteller Benutzung
- muss sich an Syntax und Zugriffskontrollen aller Klassen halten
- macht Annahmen zur gesamten Klassenhierarchie
Semantische Integrität von Unterklassen
Unterklassen müssen Spezialisierungen der Oberklassen sein. Sie müssen sich in allen semantischen Belangen wie die Oberklasse verhalten.
Vorteile
- Existierende Methoden können
- benutzt werden
- komplett überschrieben werden
- überschrieben und die Methode der Oberklasse rekursiv genutzt werden
- Existierende Funktionalität von Oberklassen können sehr einfach genutzt werden
Risiken
- Überschriebene Methoden haben eine Semantik die nicht vom Entwickler der Oberklasse oder dem Benutzer der Unterklasse verstanden werden
- Das heißt, dass die Methoden eventuell unter falschen Annahmen benutzt werden und entsprechenden Schaden anrichten
- Unterklassen erben unnötige Infrastruktur (Methoden) die den Pflegeaufwand in die Höhe treiben oder externe Benutzer verwirren
Ändern von Oberklassen
Änderungen an Oberklassen sind heikel, da sie die Implementierungen der Unterklassen invalidieren können:
- Entfernen von öffentlichen Methoden oder Attributen wird die Unterklassen invalidieren. Überschriebene Methoden werden plötzlich zu regulären. Der Polymorphismus gilt nicht für identische Methoden zweier Unterklassen wenn die Methode nicht in der Oberklasse als abstrakte Methode implementiert ist
- Nicht abstrakte Methoden abstrakt machen invalidiert die Unterklassen. Alle Unterklassen müssen die abstrakte Methode implementieren
- Hinzufügen von Methoden oder Attributen birgt das Risiko, dass sie Aufgrund zufälliger Namensgleichheit in den Unterklassen zu überschriebenen Methoden führen
Wichtig: Die Modellierung einer Klassenhierarchie muss sehr sorgfältig geschehen. Das möglichst exakte Abbilden realer Hierarchien ist für eine langlebige und wartbare Implementierung sehr wichtig.
Alternativen zur Vererbung
Vererbung birgt auch Risiken da eine Klassenhierarchie relativ starr ist und individuelle Änderungen weitreichende Auswirkungen haben können.
Vererbung sollte immer dann eingesetzt werden wenn man eine "ist-ein" Beziehung modellieren möchte.
In vielen Fällen liegt aber auch eine "hat-ein" Beziehung vor, eine Assoziation. Hier sollte man erwägen zwei Objekte zu erzeugen und sie über eine Referenz zu verwalten.
Im vorhergehen Beispiel ist es eine Überlegung wert, das Budget der Klasse Manager als Referenz von der Klasse Employee auf eine Klasse Budget zu implementieren. Hierbei sind die folgenden Dinge abzuwägen:
- Nachteile der Assoziation
- Höherer initialer Implementierungsaufwand zur Datenkaspelung
- Referenz + Zugriffsmethoden + Belegung im Konstruktor mit Objekterzeugung des Budgets
- Jeder zusätzliche Aspekt der Klasse muss als Assoziation implementiert werden
- Zusätzliche Aspekte der Klasse sind nicht in der Klassenhierarchie sichtbar
- Zusätzlicher Speicherverbrauch durch zusätzliche Objekte
- Höherer initialer Implementierungsaufwand zur Datenkaspelung
- Vorteile der Assoziation
- Zukünftige Änderungen der assoziierten Klasse haben weniger Einfluss auf die gesamte Klassenhierarchie
- Der Implementierungs-Overhead einer eigenen Klasse entfällt (Konstruktoren, überschriebene Methoden etc.)
- 11123 views
8.6 Übungen
8.6 Übungen
8.6.1 Aufruf von überschriebenen MethodenImplementieren sie die Klasse TopClass mit den folgenden Eigenschaften
|
Implementieren Sie die Klasse LowClass welche aus TopClass abgeleitet mit den folgenden Eigenschaften
Implementieren Sie ein Hauptprogramm, dass folgende Befehle ausführt
|
Zu beobachten:
- Wieviel Instanzen welcher Klasse (TopClass, LowClass) wurden erzeugt?
- Wieviel Instanzen wurden insgesamt erzeugt?
- Was geschieht wenn das Attribut zaehler der Klasse LowClass gelöscht wird?
Methode zum Testen
Nutzen Sie die main() Methode der Klasse LowClass zum Testen:
public static void main(String[] args) { int size = 3; TopClass[] feldT = new TopClass[size]; LowClass[] feldL = new LowClass[size]; for ( int i=0; i<size; i++) feldT[i]= new TopClass(); for ( int i=0; i<size; i++) { feldL[i]= new LowClass(); feldL[i].test(); } System.out.println(TopClass.getZaehler() + " Instanzen TopClass generiert, "+ LowClass.getZaehler() + " Instanzen LowClass generiert"); }
8.6.2 Vererbung und Assoziation
Implementieren Sie eine Klasse Point mit den folgenden Eigenschaften:
- private Fliesskommaattribute für x und y Koordinate
- öffentlicher Konstruktor mit x und x als Parameter
- öffentliche setXY(x,y) Methode
- Auslesemethoden getX(), getY()
- print() Methode die eine Zeichenkette mit allen Werten liefert
- überschreiben die die toString() Methode von Object so das sie alle Werte für Point ausgibt.
Implementieren Sie eine Klasse CircleIsPoint die die Eigenschaften der Klasse Point hat und zusätzlich einen Radius verwalten kann mit folgenden Eigenschaften:
- erbt von Point
- das des Zentrum des Kreises sind die (x,y) Koordinaten von Point
- privates Fliesskomma Attribut für den Radius radius
- getRadius() und setRadius(r) Methoden zum Pflegen des Attributs
- öffentlicher Konstruktor für (x,y) Zentrum und Radius
- print() Methode die eine Zeichenkette mit allen Werten liefert
- überschreiben die die toString() Methode von Object so das sie alle Werte für Point ausgibt.
Implementieren Sie eine Klasse CircleHasPoint die die Eigenschaften der Klasse Point hat und zusätzlich einen Radius verwalten kann mit folgenden Eigenschaften:
- erbt nicht von Point
- benutzt privates Attribut vom Referenztyp auf Point
- das des Zentrum des Kreises sind die (x,y) Koordinaten von Point
- alle öffentlichen Methoden sind identisch zu CircleIsPoint!
Was unterscheidet beide Implementierungen? Welche ist die bessere Implementierung?
Klasse Main
Die drei obigen Klassen sollten mit der folgenden main() Methode in CircleIsPoint funktionieren:
package s1.block9; public class Main { public static void main(String[] args) { Point p1 = new Point (2.2, 3.3); Point p2 = new Point (2.22, 3.33); CircleIsPoint cip1 = new CircleIsPoint(4.4,5.5,6.6); p1.print(); cip1.print(); CircleHasPoint chp1 = new CircleHasPoint(44.4,55.5,66.6); chp1.print(); } }
8.6.3 Flughafenbeispiel
Die Referenzimplementierung ist im GitHub Repository dhbwjava im Block 8 zu finden.
- 9518 views
8.7 Lösungen
8.7 Lösungen8.7.1 Vererbung und Überschreiben
Klasse TopClass
package s1.block8; public class TopClass { protected static int zaehler; public TopClass() {zaehler++;} protected static int getZaehler() {return zaehler;} }
Klasse LowClass
public class LowClass extends TopClass { protected static int zaehler; public LowClass() {zaehler++;} protected static int getZaehler() {return zaehler;} protected void test (){ System.out.println( getZaehler() + " Instanzen der Klasse LowClass erzeugt"); System.out.println( TopClass.getZaehler() + " Instanzen der Klasse TopClass erzeugt"); } public static void main(String[] args) { int size = 3; TopClass[] feldT = new TopClass[size]; LowClass[] feldL = new LowClass[size]; for ( int i=0; i<size; i++) feldT[i]= new TopClass(); for ( int i=0; i<size; i++) { feldL[i]= new LowClass(); feldL[i].test(); } System.out.println(TopClass.getZaehler() + " Instanzen TopClass generiert, "+ LowClass.getZaehler() + " Instanzen LowClass generiert"); } // Ende Methode main() } // Ende Klasse LowClass
Ausgaben (mit Attribut zaehler in Klasse LowClass)
1 Instanzen der Klasse LowClass erzeugt 4 Instanzen der Klasse TopClass erzeugt 2 Instanzen der Klasse LowClass erzeugt 5 Instanzen der Klasse TopClass erzeugt 3 Instanzen der Klasse LowClass erzeugt 6 Instanzen der Klasse TopClass erzeugt 6 Instanzen TopClass generiert, 3 Instanzen LowClass generiert
Ausgaben (ohne Attribut zaehler in Klasse LowClass)
5 Instanzen der Klasse LowClass erzeugt 5 Instanzen der Klasse TopClass erzeugt 7 Instanzen der Klasse LowClass erzeugt 7 Instanzen der Klasse TopClass erzeugt 9 Instanzen der Klasse LowClass erzeugt 9 Instanzen der Klasse TopClass erzeugt 9 Instanzen TopClass generiert, 9 Instanzen LowClass generiert
8.7.2 Vererbung und Assoziation
Klasse Point
package s1.block8; public class Point { private double x; private double y; public Point(double xx, double yy) { x = xx; y = yy; } public void setXY(double xx, double yy) { x = xx; y = yy; } public double getX() { return x;} public double getY() { return y;} public void print() {System.out.println(toString());} public String toString() {return ("x: " + x + " y: " + y);} }
Klasse CircleIsPoint
package s1.block8; public class CircleIsPoint extends Point{ private double radius; public CircleIsPoint(double xx, double yy, double r) { super(xx,yy); radius=r; } public double getRadius() {return radius;} public void setRadius(double r) {radius=r;} public String toString() {return (super.toString() + " , r: " + radius);} }
Klasse CircleHasPoint
package s1.block8; public class CircleHasPoint { private double radius; private Point p; public CircleHasPoint(double xx, double yy, double r) { p = new Point(xx,yy); radius=r; } public double getRadius() {return radius;} public void setRadius(double r) {radius=r;} public void setXY(double xx, double yy) { p.setXY(xx,yy);} public double getX() { return p.getX();} public double getY() { return p.getY();} public void print() {System.out.println(toString());} public String toString() {return ("x: " + p.getX() + " y: " + p.getY() + " r: "+ radius);} }
Klasse Main
package s1.block8; public class Main { public static void main(String[] args) { Point p1 = new Point (2.2, 3.3); Point p2 = new Point (2.22, 3.33); CircleIsPoint cip1 = new CircleIsPoint(4.4,5.5,6.6); p1.print(); cip1.print(); CircleHasPoint chp1 = new CircleHasPoint(44.4,55.5,66.6); chp1.print(); } }
Ausgabe:
x: 2.2 y: 3.3 x: 4.4 y: 5.5 radius: 6.6 x: 44.4 y: 55.5 radius: 66.6
8.7.3 Beispiel der Vorlesung
Schritt 1: Klonen der Klasse Ware zu Buch und Anpassen
Klasse Buch (nicht von Ware abgeleitet!)
package s1.block8; /** * Dies ist die Dokumentation der Klasse Ware. Ware dient zum Verwalten von Gütern * mit Preisen und Namen in einem Lager. * @author Stefan Schneider * @version 1.2 * @see Lager */ public class Buch { /* * 1. Erzeugen Sie eine Klasse Buch in dem Sie die Klasse * Ware mit Ihrem Inhalt kopieren * 1.1 Anpassen Name * 1.2 Anpassen Konstruktoren * 1.3 Anpassen equals Methode * 1.4 Anlegen einer ISBN Nummer * 1.5 Anlegen einer hardcodierten halben Mehrwertsteuer * 1.6 Referenz auf eine private, optionale (ältere) Auflage * Zugriffsmethoden anlegen * 1.7 Anpassen der Druckenmethode * 4. Ableiten der Klasse aus der Klasse aus der Klasse Ware * 4.1 extends Schlüsselwort benutzen * 4.2 Löschen von allem redundanten Code * 6. Erzeugen er Klasse MusikCD durch Kopieren der Klasse Ware * 6.1 Mehrwertsteuer auf vollen Mehrwertsteuer hart kodieren * 7. Die Klasse Ware soll nicht mehr instanziiert werden. Sie soll * abstrakt werden */ /** * Der aktuelle Mehrwertsteuersatz 2010. * Er liegt zur Zeit bei {@value}. * * @since 1.0 */ public static final double mws = 0.19; private double nettoPreis; //Deklaration private boolean halbeMws; private String name; public Buch empfehlung; private String isbn; private Buch alteAuflage; /** * Referenz aus alte Auflage * @return */ public Buch getAlteAuflage() { return alteAuflage; } /** * zuweisen einer alten Auflage * @param alteAuflage */ public void setAlteAuflage(Buch alteAuflage) { this.alteAuflage = alteAuflage; } /** * Auslesen der ISBN-Nummer (eine Zeichenkette) * @return */ public String getISBN() { return isbn; } /** * Konstruktor fuer die Klasse Ware * @param n der Name der Ware * @param np der Nettopreis * @param myISBN die ISBN Nummer */ public Buch(String n, double np, String myISBN) { name = n; nettoPreis = np; halbeMws = true; //Bei Büchern immer der Fall isbn=myISBN; // zusätzliche Initialiserungen.... } /** * tiefes Vergleichen. Berücksichtigt beim Namen nicht * die Groß/kleinschreinung. Berücksichtigt rekursiv die * Empfehlungen * @param dieAndereWare * @return wahr wenn beide Waren dem Vergleich entsprechen. */ public boolean equals(Buch dieAndereWare) { boolean result; result = getName().equalsIgnoreCase(dieAndereWare.getName()) && (getNettoPreis() == dieAndereWare.getNettoPreis()) && (getHalbeMws() == dieAndereWare.getHalbeMws()) && (((getEmpfehlung() == null) && (dieAndereWare.getEmpfehlung() == null)) || ((getEmpfehlung() != null) && (dieAndereWare.getEmpfehlung() != null) && (getEmpfehlung().equals(dieAndereWare.getEmpfehlung())) ) && (isbn.equals(dieAndereWare.isbn)) && (((alteAuflage == null) && (dieAndereWare.alteAuflage == null)) || ((alteAuflage != null) && (dieAndereWare.alteAuflage != null) && (alteAuflage.equals(dieAndereWare.alteAuflage)) ) ) ); return result; } /** * Liefert den Namen einer Ware zurueck. * @return Name der Ware */ public String getName() { return name; } /** * Setzen eines neuen Nettopreis * @param npr der neue Nettopreis */ public void setNettoPreis(double npr) { nettoPreis = npr; } /** * liefere wahr zurück wenn Mwssatz reduziert ist * @return */ public boolean getHalbeMws() {return halbeMws;} public Buch getEmpfehlung() { return empfehlung; } public void setEmpfehlung(Buch empfehlung) { this.empfehlung = empfehlung; } /** * Ausdrucken aller Werte auf der Konsole */ public void drucken() { drucken(0); } /** * Ausdrucken aller Werte auf der Konsole mit vorgebener Einrueckung * für Empfehlungen * @param einruecken eingerueckte Stellen für Empfehlungen */ private void drucken(int einruecken) { String leerStellen = ""; for (int i = 0; i < einruecken; i++) { leerStellen = leerStellen + " "; } System.out.print(leerStellen + "Name: " + getName()); System.out.print(" ;Netto: " + getNettoPreis()); System.out.print(" ;Brutto: " + getBruttoPreis()); if (halbeMws) System.out.println(" (Halbe Mws)"); else System.out.println(" (Volle Mws)"); if (empfehlung != null) { System.out.println(leerStellen + "Empfehlung:"); empfehlung.drucken(einruecken + 2); } System.out.println(leerStellen + "ISBN:" +isbn); if (alteAuflage != null) { System.out.println(leerStellen + "Alte Auflage:"); alteAuflage.drucken(einruecken + 2); } } /** * Ausgabe des Nettopreis * @return der Nettopreis */ public double getNettoPreis() { return nettoPreis; } /** * Ausgabe des Bruttopreis * @return der Bruttopreis */ public double getBruttoPreis() { double bp; //temporaere Variable; keine Klassenvariable if (halbeMws) { bp = Math.round(nettoPreis * (mws / 2 + 1) * 100) / 100; } else { bp = Math.round(nettoPreis * (mws + 1) * 100) / 100; } return bp; } /** * Erzeugt verkette Liste von Empfehlungen * @param empf Anzahl Empfehlungen */ public void generiereEmpfehlungen(int empf) { Buch ware1 = this; Buch ware2; for (int i = 1; i <= empf; i++) { ware2 = new Buch(ware1.getName() + " besser" + i, 31.12, isbn+"-1"); ware1.setEmpfehlung(ware2); ware1 = ware2; } } }
Klasse Main
package s1.block8; /** * Eine Hilfsklasse zur Implementierung eines Hauptprogramms * @author s@scalingbits.com * @version 1.1 */ public class MainWare { /** * Die Methode wareTesten testet die Implementierung der * von Waren mit tiefem Kopieren, tiefem Vergleichen. * Sie nutzt nicht die Vererbung aus. */ public static void warenTesten() { Ware ware1, ware2; Lager dasLager; // Testen der Klasse Ware ware1 = new Ware("Zeitung", 12.12, true); ware1.drucken(); double p = ware1.getNettoPreis(); // Generieren von Empfehlungen ware2 = new Ware("Potter Band 1", 31.12, false); ware2.generiereEmpfehlungen(7); // Abfrage des Lagers dasLager = Lager.getLager(); dasLager.einlagern(ware1, 0); dasLager.einlagern(ware2, 1); // Prüfen der Lagerbestände mit tiefem Vergleichen Ware testWare = dasLager.holen(0); if (testWare == ware2) System.out.println("testware und ware2 sind identisch (gut)"); if (testWare.equals(ware2)) System.out.println("testware und ware2 sind inhaltsgleich (gut)"); // vollständiges Befüllen des Lager for (int i = 0; i < 1000; i++) { ware2 = new Ware("Band" + i + "B", 12.12, true); ware2.generiereEmpfehlungen(7); dasLager.einlagern(ware2); } System.out.println("Lager vollständig gefüllt mit " + dasLager.lagerGroesse() + " Waren."); for (int i = 0; i < 1000; i++) { ware2 = new Ware("Volume" + i + "B", 12.12, true); ware2.generiereEmpfehlungen(7); dasLager.einlagern(ware2,i); } System.out.println("Lager erneut vollständig gefüllt mit " + dasLager.lagerGroesse() + " Waren."); } /** * Diese Methode dient zum Testen der Klasse Buch. * Sie nutzt die Veererbung in Java aus. */ public static void buecherTesten() { /* * 2. Testen: Anlegen einer Testmethode für Bücher * Erzeugen von Büchern * Anlegen einer Referenz auf eine alte Auflage * Drucken zweier Bücher * 3. Frage: Wie kann man Bücher in das Lager einfügen? * 5. Einfügen der Bücher in das Lager * 8. Anpassen der Hauptroutine * 8.1 Alle Instanzen vom Typ Ware sollen MusikCDs werden da die Klasse * Ware jetzt abstrakt ist. */ Lager dasLager; dasLager = Lager.getLager(); Buch buch1 = new Buch("Das Grauen",22.22,"9876543"); Buch buch2 = new Buch("Das Kapital",33.33,"9876543"); buch1.setAlteAuflage(buch2); buch1.drucken(); //dasLager.einlagern(buch1); //dasLager.einlagern(buch2); dasLager.drucken(); } /** * Das Hauptprogramm * * @param args */ public static void main(String[] args) { //warenTesten(); buecherTesten(); } }
Schritt 2: Die Klasse Buch wird aus der Klasse Ware abgeleitet
Klasse Buch
package s1.block8; /** * Dies ist die Dokumentation der Klasse Ware. Ware dient zum Verwalten von Gütern * mit Preisen und Namen in einem Lager. * @author Stefan Schneider * @version 1.2 * @see Lager */ public class Buch extends Ware { /* * 1. Erzeugen Sie eine Klasse Buch in dem Sie die Klasse * Ware mit Ihrem Inhalt kopieren * 1.1 Anpassen Name * 1.2 Anpassen Konstruktoren * 1.3 Anpassen equals Methode * 1.4 Anlegen einer ISBN Nummer * 1.5 Anlegen einer hardcodierten halben Mehrwertsteuer * 1.6 Referenz auf eine private, optionale (ältere) Auflage * Zugriffsmethoden anlegen * 1.7 Anpassen der Druckenmethode * 4. Ableiten der Klasse aus der Klasse aus der Klasse Ware * 4.1 extends Schlüsselwort benutzen * 4.2 Löschen von allem redundanten Code * 6. Erzeugen er Klasse MusikCD durch Kopieren der Klasse Ware * 6.1 Mehrwertsteuer auf vollen Mehrwertsteuer hart kodieren * 7. Die Klasse Ware soll nicht mehr instanziiert werden. Sie soll * abstrakt werden */ /** * Der aktuelle Mehrwertsteuersatz 2010. * Er liegt zur Zeit bei {@value}. * * @since 1.0 */ private String isbn; private Buch alteAuflage; /** * Referenz aus alte Auflage * @return */ public Buch getAlteAuflage() { return alteAuflage; } /** * zuweisen einer alten Auflage * @param alteAuflage */ public void setAlteAuflage(Buch alteAuflage) { this.alteAuflage = alteAuflage; } /** * Auslesen der ISBN-Nummer (eine Zeichenkette) * @return */ public String getISBN() { return isbn; } /** * Konstruktor fuer die Klasse Ware * @param n der Name der Ware * @param np der Nettorpreis * @param hmws halber Mehrwertsteuersatz für Ware gueltig */ public Buch(String n, double np, String myISBN) { super(n,np,true); isbn=myISBN; // zusätzliche Initialiserungen.... } /** * tiefes Vergleichen. Berücksichtigt beim Namen nicht * die Groß/kleinschreinung. Berücksichtigt rekursiv die * Empfehlungen * @param dieAndereWare * @return wahr wenn beide Waren dem Vergleich entsprechen. */ public boolean equals(Buch dieAndereWare) { boolean result; result = super.equals((Ware)dieAndereWare) && (isbn.equals(dieAndereWare.isbn)) && (((alteAuflage == null) && (dieAndereWare.alteAuflage == null)) || ((alteAuflage != null) && (dieAndereWare.alteAuflage != null) && (alteAuflage.equals(dieAndereWare.alteAuflage)) ) ); return result; } /** * Ausdrucken aller Werte auf der Konsole mit vorgebener Einrueckung * für Empfehlungen * @param einruecken eingerueckte Stellen für Empfehlungen */ protected void drucken(int einruecken) { super.drucken(einruecken); String leerStellen = ""; for (int i = 0; i < einruecken; i++) { leerStellen = leerStellen + " "; } System.out.println(leerStellen + "ISBN:" +isbn); if (alteAuflage != null) { System.out.println(leerStellen + "Alte Auflage:"); alteAuflage.drucken(einruecken + 2); } } }
Klasse MainBuch
Die Instanzen der Klasse Buch können jetzt in das Lager eingefügt werden
package s1.block8; /** * Eine Hilfsklasse zur Implementierung eines Hauptprogramms * @author sschneid */ public class MainBuch { /** * Die Methode wareTesten testet die Implementierung der * von Waren mit tiefem Kopieren, tiefem Vergleichen. * Sie nutzt nicht die Vererbung aus. */ public static void warenTesten() { Ware ware1, ware2; Lager dasLager; // Testen der Klasse Ware ware1 = new Ware("Zeitung", 12.12, true); ware1.drucken(); double p = ware1.getNettoPreis(); // Generieren von Empfehlungen ware2 = new Ware("Potter Band 1", 31.12, false); ware2.generiereEmpfehlungen(7); // Abfrage des Lagers dasLager = Lager.getLager(); dasLager.einlagern(ware1, 0); dasLager.einlagern(ware2, 1); // Prüfen der Lagerbestände mit tiefem Vergleichen Ware testWare = dasLager.holen(0); if (testWare == ware2) System.out.println("testware und ware2 sind identisch (gut)"); if (testWare.equals(ware2)) System.out.println("testware und ware2 sind inhaltsgleich (gut)"); // vollständiges Befüllen des Lager for (int i = 0; i < 1000; i++) { ware2 = new Ware("Band" + i + "B", 12.12, true); ware2.generiereEmpfehlungen(7); dasLager.einlagern(ware2); } System.out.println("Lager vollständig gefüllt mit " + dasLager.lagerGroesse() + " Waren."); for (int i = 0; i < 1000; i++) { ware2 = new Ware("Volume" + i + "B", 12.12, true); ware2.generiereEmpfehlungen(7); dasLager.einlagern(ware2,i); } System.out.println("Lager erneut vollständig gefüllt mit " + dasLager.lagerGroesse() + " Waren."); } /** * Diese Methode dient zum Testen der Klasse Buch. * Sie nutzt die Veererbung in Java aus. */ public static void buecherTesten() { /* * 2. Testen: Anlegen einer Testmethode für Bücher * Erzeugen von Büchern * Anlegen einer Referenz auf eine alte Auflage * Drucken zweier Bücher * 3. Frage: Wie kann man Bücher in das Lager einfügen? * 5. Einfügen der Bücher in das Lager * 8. Anpassen der Hauptroutine * 8.1 Alle Instanzen vom Typ Ware sollen MusikCDs werden da die Klasse * Ware jetzt abstrakt ist. */ Lager dasLager; dasLager = Lager.getLager(); Buch buch1 = new Buch("Das Grauen",22.22,"9876543"); Buch buch2 = new Buch("Das Kapital",33.33,"9876543"); buch1.setAlteAuflage(buch2); buch1.drucken(); dasLager.einlagern(buch1); dasLager.einlagern(buch2); dasLager.drucken(); } /** * Das Hauptprogramm * * @param args */ public static void main(String[] args) { //warenTesten(); buecherTesten(); } }
Stufe 3: Klasse MusikCD
Klasse MusikCD
package s1.block8; /** * Dies ist die Dokumentation der Klasse Ware. Ware dient zum Verwalten von Gütern * mit Preisen und Namen in einem Lager. * @author s@scalingbits.com * @version 1.3 * @see Lager */ public class MusikCD extends Ware { /* * 6. Erzeugen er Klasse MusikCD durch Kopieren der Klasse Ware * 6.1 Mehrwertsteuer auf vollen Mehrwertsteuer hart kodieren * 7. Die Klasse Ware soll nicht mehr instanziiert werden. Sie soll * abstrakt werden */ /** * Konstruktor fuer die Klasse Ware * @param n der Name der Ware * @param np der Nettorpreis * @param hmws halber Mehrwertsteuersatz für Ware gueltig */ public MusikCD(String n, double np) { super(n,np,false); } /** * tiefes Vergleichen. Berücksichtigt beim Namen nicht * die Groß/kleinschreinung. Berücksichtigt rekursiv die * Empfehlungen * @param dieAndereWare * @return wahr wenn beide Waren dem Vergleich entsprechen. */ public boolean equals(MusikCD dieAndereWare) { return super.equals((Ware)dieAndereWare); } }
Klasse MainCD
package s1.block8; /** * Eine Hilfsklasse zur Implementierung eines Hauptprogramms * @author s@scalingbits.com * @version 1.3 */ public class Main { /** * Die Methode wareTesten testet die Implementierung der * von Waren mit tiefem Kopieren, tiefem Vergleichen. * Sie nutzt nicht die Vererbung aus. */ public static void warenTesten() { Ware ware1, ware2; Lager dasLager; // Testen der Klasse Ware ware1 = new Ware("Zeitung", 12.12, true); ware1.drucken(); double p = ware1.getNettoPreis(); // Generieren von Empfehlungen ware2 = new Ware("Potter Band 1", 31.12, false); ware2.generiereEmpfehlungen(7); // Abfrage des Lagers dasLager = Lager.getLager(); dasLager.einlagern(ware1, 0); dasLager.einlagern(ware2, 1); // Prüfen der Lagerbestände mit tiefem Vergleichen Ware testWare = dasLager.holen(0); if (testWare == ware2) System.out.println("testware und ware2 sind identisch (gut)"); if (testWare.equals(ware2)) System.out.println("testware und ware2 sind inhaltsgleich (gut)"); // vollständiges Befüllen des Lager for (int i = 0; i < 1000; i++) { ware2 = new Ware("Band" + i + "B", 12.12, true); ware2.generiereEmpfehlungen(7); dasLager.einlagern(ware2); } System.out.println("Lager vollständig gefüllt mit " + dasLager.lagerGroesse() + " Waren."); for (int i = 0; i < 1000; i++) { ware2 = new Ware("Volume" + i + "B", 12.12, true); ware2.generiereEmpfehlungen(7); dasLager.einlagern(ware2,i); } System.out.println("Lager erneut vollständig gefüllt mit " + dasLager.lagerGroesse() + " Waren."); } /** * Diese Methode dient zum Testen der Klasse Buch. * Sie nutzt die Veererbung in Java aus. */ public static void buecherTesten() { /* * 2. Testen: Anlegen einer Testmethode für Bücher * Erzeugen von Büchern * Anlegen einer Referenz auf eine alte Auflage * Drucken zweier Bücher * 3. Frage: Wie kann man Bücher in das Lager einfügen? * 5. Einfügen der Bücher in das Lager * 8. Anpassen der Hauptroutine * 8.1 Alle Instanzen vom Typ Ware sollen MusikCDs werden da die Klasse * Ware jetzt abstrakt ist. */ Lager dasLager; dasLager = Lager.getLager(); Buch buch1 = new Buch("Das Grauen",22.22,"9876543"); Buch buch2 = new Buch("Das Kapital",33.33,"9876543"); buch1.setAlteAuflage(buch2); buch1.drucken(); dasLager.einlagern(buch1); dasLager.einlagern(buch2); dasLager.drucken(); } /** * Diese Methode dient zum Testen der Klasse Buch. * Sie nutzt die Veererbung in Java aus. */ public static void CDsTesten() { /* * 2. Testen: Anlegen einer Testmethode für Bücher * Erzeugen von Büchern * Anlegen einer Referenz auf eine alte Auflage * Drucken zweier Bücher * 3. Frage: Wie kann man Bücher in das Lager einfügen? * 5. Einfügen der Bücher in das Lager * 8. Anpassen der Hauptroutine * 8.1 Alle Instanzen vom Typ Ware sollen MusikCDs werden da die Klasse * Ware jetzt abstrakt ist. */ Lager dasLager; dasLager = Lager.getLager(); MusikCD cd1 = new MusikCD("Thriller",8.88); MusikCD cd2 = new MusikCD("Peter und der Wolf",9.99); cd1.setEmpfehlung(cd2); cd1.drucken(); dasLager.einlagern(cd1); dasLager.einlagern(cd2); dasLager.drucken(); } /** * Das Hauptprogramm * * @param args */ public static void main(String[] args) { //warenTesten(); buecherTesten(); CDsTesten(); } }
- 7588 views
die Zeile: public int
die Zeile:
public int price = 99;
in der Klasse CircleIsPoint ist dort sicher nur aus Versehen hineingeraten?
- Log in to post comments
8.8 Lernziele
8.8 Lernziele
Am Ende dieses Blocks können Sie:
|
Lernzielkontrolle
Sie sind in der Lage die Fragen zur Vererbung zu beantworten:
Feedback
- 4176 views