Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
könnte mir jemand sagen, wenn es 2 Klassen gibt
A - machwas()
B erbt von A - machwas()
hat wo der Unterschied zwischen
A a = new A(); und A a = new B(); ist?
Wenn ich es richtig verstanden habe dann ist doch bei A a = new B();
a immernoch ein A somit sind die beiden doch equivalent oder? Falls ja wo ist der Sinn hinter dieser Schreibweise?
Der Sinn kommt erst, wenn du noch eine Klasse C hast, die auch von A erbt
Dann kannst du deiner Methode sagen, sie bekommt ein A-Objekt übergeben, ob es sich dabei um Klasse B oder C handelt ist der Methode dann egal
Wie sollte sowas zu totalem Chaos führen? Solange die Methode das tut, was sie soll, ist doch alles passend. Interfaces zu benutzen führt ja auch nicht plötzlich zu totalem Chaos...
Der Sinn kommt erst, wenn du noch eine Klasse C hast, die auch von A erbt
Dann kannst du deiner Methode sagen, sie bekommt ein A-Objekt übergeben, ob es sich dabei um Klasse B oder C handelt ist der Methode dann egal
Wie sollte sowas zu totalem Chaos führen? Solange die Methode das tut, was sie soll, ist doch alles passend. Interfaces zu benutzen führt ja auch nicht plötzlich zu totalem Chaos...
mit a.i dürfte das afaik das A von i sein, in Methoden von B kannst du das mit this und super angeben, in A nur das i von A. Man sollte aber gleich lautende Variablen beim Erben vermeiden
Würdest du auch empfehlen, nie wieder Interfaces zu benutzen? Wenn ich da stattdessen eine Implementation benutze, kann ich schließlich auch alle Methoden des Interfaces benutzen...
Abgesehen davon kann ich eben nicht die Methoden von A oder C benutzen, B kann die schließlich anders implementiert haben.
Die Polymorphie-Diskussion gabs doch schon mal hier.
Meine 2 cents:
- Wenn c nur eine lokale oder eine private Instanzvariable ohne setter ist, ist die Deklaration als Child vollkommen ok. c als Person zu deklarieren, wenn klar ist, das ein Child gebraucht wird, ist Unfug.
- Wenn c über einen setter gesetzt werden kann, und man dem Aufrufer der Methode die Möglichkeit geben möchte, neben Child auch weitere Unterklassen von Person zu verwenden, muss c natürlich als Person deklariert werden.
Im verlinkten sehen die meisten das nicht als Unfug, und die einzige Begründung für Unfug ist "zu verwirrend"...allerdings wirkt es da eher wie "Polymorphie ist zu verwirrend"
Warum sollte denn klar sein, dass ein Child benötigt wird? Doch nur, falls das Child auf irgendeine Weise speziell ist, so dass Person nicht geeignet ist, etwa weil eine Child-Methode benötigt wird. Dann würde es mit Person ja ohnehin nicht funktionieren. Falls Person jedoch auch geeignet sein sollte, ergibt es doch keinen Sinn, sich auf ein Child festzulegen. Wundere mich etwas über die Diskussion, weil ich bisher dachte, das Prinzip "So allgemein wie möglich, so speziell wie nötig" sei völlig unstrittig.
Ich erinnerer mich an diese Diskussion. Achtung! Alles folgende ist meine persönliche Meinung: Wenn man "nichts" mit den Objekten macht, würde ich sagen dass es persönliche Präferenz ist. Person p = new Child() vs Child c = new Child(). ABER:
Da man sich ja meist in komplexeren Sytemen aufhält sieht das ganze wieder anders aus. Hier mal ein konkretes Beispiel: Familienstammbaum erstellen.
Code:
public void init()
{
StammBaum s = new StammBaum();
Child c = new Child();
Father f = new Father();
Mother m = new Mother();
s.addChild(c);
s.addFather(f);
s.addMother(m);
}
Kann man sicherlich so machen. Macht aber nur Sinn wenn die verschiedenen addXXX Methoden unterschiedliches Verhalten an den Tag legen (oder wenn es drei separate Listen für die Instanzen gibt). Wenn sie nur Instanzen hinzufügen (die nicht getrennt abgelegt werden sollen) kann eine allgemeine addPerson(Person) Methode mehr Sinn machen. Ich sage "kann" weil es immer darauf ankommt. Worauf? Ich würde sagen: Darauf wieviele Gemeinsamkeiten die einzelnen Klassen haben. Polimorphie erspart einem ja zb Code Dopplung.
Sie gibt einem aber auch die Möglichkeit gemeinsames Verhalten an die jeweilige Klasse anzupassen. Sie gar komplett anders zu handhaben.
TL;DR
Kommt in einem Projekt Polimorphie vor, wird es früher oder später die Notwendigkeit von Methoden geben, die mit der Allgemein gültigsten Klasse arbeiten werden. Daher bietet es sich an mit dieser zu arbeiten (zumindest da, wo keine "spezialisierten" Methoden etc gebraucht werden)
Zum Schluss: Ich bin außerdem der Meinung, dass "Auf Biegen und Brechen" Polimorphie einzusetzen genauso wenig die Lösung ist wie komplett darauf zu verzichten. Softwarearchitektur heisst auch zu erörtern welches "Werkzeug" oder Pattern wann einzusetzen ist.
Ehrlich, die Rückfrage verstehe ich nicht.
Wenn ich ein Child brauche (z. B. weil ich eine Child-Methode aufrufen will oder das Child an eine Methode übergeben will, die einen Child-Parameter erwartet), dann ist es Unfug, die Variable c, die ja als Child initialisiert wurde und demnach ein Child ist, als Person zu deklarieren, weil ich dann bei den oben geschilderten use cases (Methodenaufruf oder Übergabe als Parameter) immer casten müsste. Der cast des als Person deklarierten Objekts auf Child wird zwar funktionieren, aber warum sollte man sich das antun?
nur dann für sinnvoll, wenn Person nicht instanziiert werden kann, weil Person entweder eine abstrakte Klasse oder ein interface ist. Falls beides NICHT gegeben ist, gibt es zwei Fälle:
a) ich will c als Child verwenden (s. o.). Dann ist es Unfug, es als Person zu deklarieren.
b) ich will c als Person verwenden. Dann stellt sich die Frage, warum nicht direkt eine Instanz von Person erzeugt wird.
Weil ich die Implementierung von Child möchte?
Warum sollte ich mich dann, wenn ich nur irgendeine Person haben will, und es für den restlichen Code egal ist, direkt auf eine bestimmt einschränken?
Ob man es lieber allgemein oder spezieller deklariert, mag persönliche Differenz sein. Aber den allgemeinen Fall als Unfug zu bezeichnen, halte ich für Unfug
Wenn ich ein Child brauche (z. B. weil ich eine Child-Methode aufrufen will oder das Child an eine Methode übergeben will, die einen Child-Parameter erwartet), dann ist es Unfug, die Variable c, die ja als Child initialisiert wurde und demnach ein Child ist, als Person zu deklarieren, weil ich dann bei den oben geschilderten use cases (Methodenaufruf oder Übergabe als Parameter) immer casten müsste.
Natürlich ist es dann Unfug. Den Standpunkt vertritt hier aber auch niemand. Es ging um den Fall, dass A und B über die Methode machwas() verfügen, allgemein gesprochen also darum, ob man gegen interfaces programmieren soll. Das hat mit deinem Beispiel nichts zu tun.
Nein, man kann auch versuchen, das allgemein unabhängig vom konkreten Kontext zu definieren. Habe ich oben ja auch versucht und dein Beispiel passt genau in diese Definition, denn du forderst etwas Spezifisches vom Child, das Person nicht leisten kann. Wenn nichts Spezifisches gefordert wird, sollte man sich auch nicht festlegen.
Endlich habe ich die Muße gefunden und diesen Thread mal überflogen.
Also ihr redet aneinander vorbei. Was gefragt wurde: dynamic dispatching.
Was ihr zu diskutieren versucht ist z.B.: Ist es besser ArrayList<T> list = new ArrayList<>(); zu verwenden oder List<T> list = new ArrayList<>();.
Bei der Grundfrage kann man sagen, dass das der einzige Sinn von Polymorphie ist.
Bei der zweiten Frage: Es kommt immer darauf an welche Funktionalität ich gerade benötige. Falls ich konkrete Methoden einer Klasse brauche, dann nehme ich auch die konkrete Klasse.
Also, wenn wir hier nur vom simplen Objekte Erzeugen reden und sowas wie Übergabe Parameter und Generische Typen in zB Listen außer Acht lassen, würde ich sagen:
Es ist eine persönliche Präferenz wie man es nun schreibt.
zB schreibe ich immer: JFrame frame = new JFrame(); Auch in Fällen wo ich dessen spezifische Methoden wie "setDefaultCloseOperation" nicht brauche. Klar könnte ich auch Window frame = new JFrame(); schreiben... mach' ich aber nicht.
Weil ich die Implementierung von Child möchte?
Warum sollte ich mich dann, wenn ich nur irgendeine Person haben will, und es für den restlichen Code egal ist, direkt auf eine bestimmt einschränken?
Wenn ich das Verhalten von Child haben möchte, und dieses ja auch durch die Instanziierung erreiche/erzwinge, würde ich auf jeden Fall dafür plädieren, dass das auch an der Deklaration erkennbar sein sollte.
Der einzige Vorteil, den ich durch die Deklaration von c als Person erkennen kann, ist der, das nur die Zeile wo c instanziiert wird, geändert werden muss, und nicht auch die Zeile wo es deklariert wird, wenn ein anderer Typ von Person gewünscht wird.
Hier habe ich bisher stets die erste Variante verwendet. Zum einen ist jetzt auf Anhieb im Kopf der Klasse erkennbar, welche Implementierung konkret gewählt ist, und ich muss nicht den Ort der Initialisierung suchen. Ausserdem kann der Import von java.util.List gespart werden.
Gibt es zum Punkt "Deklaration von lokalen Variablen oder von Instanzvariablen, die keinerlei Relevanz für die öffentliche Schnittstelle einer Klasse haben" eigentlich offizielle Empfehlungen?
Wenn ich das Verhalten von Child haben möchte, und dieses ja auch durch die Instanziierung erreiche/erzwinge, würde ich auf jeden Fall dafür plädieren, dass das auch an der Deklaration erkennbar sein sollte.
Hier habe ich bisher stets die erste Variante verwendet. Zum einen ist jetzt auf Anhieb im Kopf der Klasse erkennbar, welche Implementierung konkret gewählt ist, und ich muss nicht den Ort der Initialisierung suchen. Ausserdem kann der Import von java.util.List gespart werden.
In den meisten Fällen ist es (zumindest mir) nicht relevant, auf welche Implementation man arbeitet. Wenn es wirklich relevant sein sollte, dann hauptsächlich, weil man spezielle Methoden braucht, und dann kommt man ehh nicht ums genaue Deklarieren drum rum.
Imports sind da aber wirklich kein Grund (und wenn man statt import java.util.ArrayListjava.util.* nutzt, spart man sogar ein paar Zeichen ).
Hier habe ich bisher stets die erste Variante verwendet. Zum einen ist jetzt auf Anhieb im Kopf der Klasse erkennbar, welche Implementierung konkret gewählt ist, und ich muss nicht den Ort der Initialisierung suchen. Ausserdem kann der Import von java.util.List gespart werden.
Erklär doch mal welchen Vorteil dir das bringt? Als Frameworkentwickler musst du immer Implementierungsfrei arbeiten und das geht nur mit Interfaces. Denn wenn du einmal was auswechseln möchtest musst du es an allen! Codestellen dann ändern und nicht nur bei der "anscheinend" schwer zu findenden Stelle bei der Initialisierung.
Reden wir über die öffentliche Schnittstelle einer Klasse, oder über die Deklaration von privaten Variablen, die nur die interne Implementierung relevant und für die öffentliche Schnittstelle ohne Bedeutung sind?
Was? Ich schliesse jetzt mal aus, dass du damit meinst, eine private Instanzvariable könnte schnell mal public werden.
Wenn eine private Variable zum Bestandteil der öffentlichen API wird, dann doch mit Sicherheit nur über setter und getter. Dann sollten die Rückgabewerte bzw. Methodenparameter in der Tat keine unnötig spezielle Deklaration haben. Um auf das Beispiel mit der privaten ArrayList zurückzukommen: der Rückgabewert eines getters sollte in > 99% aller Fälle nicht als ArrayList deklariert werden.
[edit] Kann man die letzten beiträge vielleicht in einen neuen thread verschieben?
Wenn eine private Variable zum Bestandteil der öffentlichen API wird, dann doch mit Sicherheit nur über setter und getter. Dann sollten die Rückgabewerte bzw. Methodenparameter in der Tat keine unnötig spezielle Deklaration haben
Trotzdem sollte man in der internen API so allgemein/abstrakt wie möglich bleiben. Denn Code entwickelt sich weiter und dann hat man den Salat, aber eben später.