Java-Polymorphismus Verwirrung

8

Die folgende Frage stammt aus dem Java SCJP5-Buch von Kathy Sierra und Bert Bates. Eine Methode angegeben als:

%Vor%

Ein Programmierer möchte die Methode so verwenden:

%Vor%

Welches Deklarationspaar könnte bei // INSERT DECLARATIONS HERE platziert werden, damit der Code kompiliert werden kann? (Wählen Sie alle zutreffenden Antworten aus.)

A.

%Vor%

B

%Vor%

C.

%Vor%

D.

%Vor%

E

%Vor%

F.

%Vor%

G. Keine der oben genannten.

Korrekte Antworten sind: B, E, F und die Erklärung im Buch:
"Der Rückgabetyp ist definitiv als List deklariert, NICHT als ArrayList, also sind A, D falsch. ......"

Das ist, was ich nicht verstehe ... warum es ist, dass der Rückgabetyp nur List sein muss und nicht ArrayList? Genau wie das Argument ArrayList sein kann, warum kann nicht zurück geben auch arrayList sein?

Danke

    
msharma 13.05.2009, 15:31
quelle

8 Antworten

3

Dies ist eigentlich nicht spezifisch für Generika, sondern betrifft Typen.

Man kann es sich so vorstellen: ArrayList ist List , aber List ist nicht unbedingt ArrayList .

ArrayList implementiert das Interface List , so dass es als List behandelt werden kann. Nur weil etwas List implementiert, ist es kein ArrayList . Zum Beispiel implementiert LinkedList List , ist aber kein ArrayList .

Zum Beispiel sind folgende erlaubt:

%Vor%

Dies liegt daran, dass sowohl ArrayList als auch LinkedList beide die Schnittstelle List implementieren, so dass beide als List s behandelt werden können.

Folgendes ist jedoch nicht erlaubt:

%Vor%

Obwohl sowohl ArrayList als auch LinkedList List implementieren, sind sie nicht dieselbe Klasse. Sie können Ähnlichkeiten aufweisen, indem sie die Methoden von List implementieren, aber sie sind vollständig separate Klassen.

    
coobird 13.05.2009, 15:39
quelle
13

Da ArrayList eine Unterklasse von List ist, ist die vom Prozess zurückgegebene Liste nicht garantiert eine ArrayList. Zum Beispiel könnte es stattdessen eine LinkedList sein.

    
starblue 13.05.2009 15:36
quelle
3

Wenn Sie eine Rückgabe vom Typ List angeben, sagen Sie, dass die Rückgabe eine beliebige -Liste sein kann, egal ob es sich um eine ArrayList, eine LinkedList oder eine andere Art von List handelt. Wenn Sie versuchen, eine ArrayList zurückzugeben, sind Sie zu spezifisch - es ist keine generische Liste mehr.

    
Tim 13.05.2009 15:37
quelle
3

Der Rückgabetyp könnte eine ArrayList sein, aber es könnte auch keine ArrayList sein, es könnte eine LinkedList, ein Wrapper einer Collections List oder andere Dinge sein. Um es einer Variablen zuzuweisen, müssen Sie entweder den Typ der höchsten Ebene verwenden, der in diesem Fall (in diesem Fall List) sein könnte, oder den Downcast, wenn Sie wissen, dass eine ArrayList sein muss.

In der Praxis sollten Variablen fast immer als Liste (wenn nicht Sammlung) eingegeben werden. Es gibt fast nie einen guten Grund, sich auf den konkreten Typ für diese Klassen zu beziehen.

Der einzige Grund, an den ich denken kann, ist, wenn Sie eine Methode haben, die einen wahlfreien Zugriff auf eine Liste erfordert und Sie sicherstellen wollen, dass Sie aus Performancegründen keine LinkedList erhalten und die Liste zu groß ist, um sie vernünftig in eine ArrayList zu kopieren für den Zweck des wahlfreien Zugriffs.

    
Yishai 13.05.2009 15:46
quelle
1

Sie können den Rückgabetyp als ArrayList deklarieren, aber es würde eine explizite Umwandlung wie folgt erfordern:

%Vor%

... was im Gegensatz zu dem steht, was Generika Ihnen ermöglichen.

    
Cuga 13.05.2009 15:47
quelle
1

Die Methode process wird nicht in der Lage sein zu entscheiden, welche konkrete Implementierung von List zu wählen ist. Seine Signatur gibt Ihnen das Versprechen, dass es in der Lage ist, auf einer beliebigen Liste (ArrayList, LinkedList, etc ...) zu arbeiten und kann nur angeben, dass der Rückgabewert eine SOME-Liste sein wird.

Wenn das zurückgegebene Objekt beispielsweise eine LinkedList ist, können Sie es nicht direkt einer Variablen zuweisen, die als ArrayList deklariert ist. Sie können sie jedoch als List behandeln. Daher sind A. und D. nicht korrekt. Sie können Ihre Variable nicht als ArrayList deklarieren lassen.

    
Peter Perháč 13.05.2009 15:38
quelle
0

Dies liegt daran, dass die Frage explizit besagt, dass die Methode List & lt; T & gt; zurückgibt. Sie können sehr gut die Methodendefinition ändern, um ArrayList & lt; T & gt; zurückzugeben, aber das ist eine andere Frage. Eine Liste & lt; T & gt; kann viele verschiedene Arten von Liste sein.

    
krosenvold 13.05.2009 15:37
quelle
0

Eine andere Möglichkeit, dies zu betrachten, ist "Zuweisungskompatibilität". Semantisch der Methodenaufruf

%Vor%

entspricht

%Vor%

Wir wissen, dass nums den Typ List<E> hat, also muss der Typ input " List<E> " zuweisbar sein. Ebenso wissen wir, dass returnVal (d. H. Der Rückgabewert von process ) Typ List<E> , also List<E> muss dem Typ von output "zuweisbar" sein.

Im Allgemeinen ist ein Typ T einem Typ U "zuweisbar", wenn T ein Untertyp von U ist (einschließlich des Falles, in dem T und U identisch sind).

Daher muss der Typ von input List<E> oder ein Subtyp von List<E> sein (z. B. ArrayList<E> oder LinkedList<E> ). Ebenso muss der Typ von output List<E> oder ein Supertyp von List<E> sein (z. B. Collection<E> oder sogar Object ).

    
Chris Conway 13.05.2009 20:25
quelle

Tags und Links