Collections?

2 Antworten

Soweit ich weiss, ist dies upcasting und so müsse sich doch Collection<Integer> stack =  new Stack<>() wie ein stack verhalten oder nicht,da doch zum Beipsiel die add Methode vom interface durch new Stack veränderd wird

Casting verändert nicht das zugrundeliegende Objekt, nur den Typ der referenzierenden Variable. In deinem Fall stehen dir daher nur mehr die Methoden von Collection zur Verfügung, nicht aber die zusätzlichen, spezifischen Methoden von Stack (push/pop/peek etc.).

da doch zum Beipsiel die add Methode vom interface durch new Stack veränderd wird

Inwiefern?

Vielleicht kannst du anhand eines konkreten Beispiels zeigen, warum du glaubst, dass add() sich im Verhalten ändert. Tut es nämlich nicht: https://github.com/openjdk/jdk17/blob/master/src/java.base/share/classes/java/util/Stack.java

SchwitzerFrage 
Fragesteller
 01.10.2023, 12:44
  1. achso.Also stack überschreibt die Methode add ja nicht,also bleibt sie so,wie in sie ist?
  2. wieso sollte man dann in diesem Fall überhaupt Collection<Integer> stack = new Stack<>() machen ,wenn ich die stack methoden gar nicht benutzen kann?
0
jo135  01.10.2023, 12:51
@SchwitzerFrage

Ja, sie bleibt so, wie sie im Vector implementiert wurde, von dem Stack abgeleitet ist. Übrigens sind Vector und Stack uralte Klassen, die man heute eher nicht mehr verwenden würde. Sie sind nur mehr im JDK, um rückwärtskompatibel zu bleiben.

Zu deiner zweiten Frage: in dieser Form ergibt das natürlich keinen Sinn.

Aber wenn du Code schreibst, der mit allen Collections umgehen soll, kannst du natürlich nicht vorher alle möglichen Implementierungen wissen, die dann tatsächlich durchgeschickt werden. Das ist ja Sinn der Polymorphie.

Ein anders gelagerter Fall ist es im häufigen Muster:

List<String> l = new ArrayList<>();

Hier arbeitest du bewusst mit dem Interface, weil es für den restlichen Code keine Rolle spielt, welche Implementierung von List verwendet wird. Aber Liste ist Liste, zumindest vom Interface her.

1

Beim Upcasting sind nur die Methoden der Oberklasse aufrufbar, sodass die der Unterklasse nicht mehr zugänglich sind. Beim Downcasting hingegen kann man sowohl auf die Methoden der Ober- als auch Unterklasse zugreifen. Casting hat keine Aufwirkung auf das Objekt an sich, sondern „benennt“ nur das Objekt anders.

Beispiel: Ein Objekt h der Klasse Hund besitzt die Methode bellen(). Da Hund eine Unterklasse von Tier ist, hat h Zugriff auf die Methoden von Hund und auch Tier. Beim Upcasting von h zur Oberklasse Tier bleibt das Objekt h an sich unverändert, aber h wird nun wie ein Tier-Objekt „behandelt“, wodurch auf die unterklassenspezifische Methode bellen() nicht mehr zugegriffen werden kann.

Stack<Integer> stack = new Stack<>();

Wie Du bereits sagtest, verhält sich stack logischerweise wie Stack, da der Variable vom Typ Stack ein Stack-Objekt zugewiesen wird.

Collection<Integer> stack = new Stack<>();

Diese Zuweisung eines Stack-Objekts zu einer Variable vom Typ Collection ist möglich, da das Interface Collection die Klasse Stack implementiert. Durch das Casting des Stack-Objekts zu einer Collection verhält sich stack nicht mehr wie ein Stack, sondern wie eine Collection, obwohl stack immer noch ein Stack-Objekt zugrundeliegt. Die Variable stack hat damit keinen Zugriff mehr auf die Methoden der Stack-Klasse, also z. B. push() oder pop().

Die add()-Methode wird in der Stack-Klasse nicht überladen. Da Stack von Vector abgeleitet ist, wird add() von der Oberklasse geerbert.

Weist man einer Variable vom Typ Collection ein Stack-Objekt zu, hat man den Vorteil, dass sich bei Bedarf die Implementierung des Collection-Interface einfach austauschen lässt und dadurch die Flexibilität erhöht wird. Aus diesem Grunde schreibt man auch grundsätzlich:

List<String> list = new ArrayList<String>();

statt:

ArrayList<String> list = new ArrayList<String>();

Wenn man die Implementierung ändern möchte (z. B. in eine LinkedList), hätte die zweite Variante den Nachteil, dass an jeder Stelle ArrayList in LinkedList geändert werden müsste. Bei der ersten Variante würde man sich den Anpassungsaufwand im restlichen Code ersparen. Daher empfiehlt es sich, gegen eine Schnittstelle bzw. einen Interface (Collection oder List) zu programmieren statt gegen eine Implementierung (Stack oder ArrayList/LinkedList).