Was ist der Vorteil von Polymorphie, die die Collection-Schnittstelle verwendet, um ein ArrayList-Objekt zu erstellen?

8

Ich habe Polymorphismus studiert und verstanden, dass er dynamische Methoden wie unten beschreiben kann.

Angenommen, die Klasse Animal ist eine abstrakte Klasse.

%Vor%

Ich habe eine Instanz von ArrayList erstellt wie:

%Vor%

Aber normalerweise dachte ich, dass die Leute schreiben:

%Vor%

Also ist meine Verwirrung, was ist der Vorteil, als Sammlung zu deklarieren? Auch ich wusste nicht, dass Sie "Sammlung" (die eine Schnittstelle nicht abstrakte Klasse ist) vor "myList" haben können.

Warum es nicht gut ist, einfach zu sagen:

%Vor%

Ich lese Collection-Interface und ArrayList Java-Dokumente sowie Online-Tutorials aber immer noch nicht wirklich klar .. Könnte mir jemand eine Erklärung geben?

    
masato-san 28.07.2010, 18:23
quelle

8 Antworten

10

Wenn Sie myList als ArrayList deklarieren, korrigieren Sie den konkreten Typ. Jeder, der es benutzt, hängt von diesem konkreten Typ ab, und es ist leicht, Methoden aufzurufen, die für ArrayList spezifisch sind (sogar unabsichtlich). Wenn Sie sich später entscheiden, es z. LinkedList oder CopyOnWriteArrayList müssen Sie den Client-Code neu kompilieren - und möglicherweise sogar ändern. Die Programmierung für Schnittstellen beseitigt dieses Risiko.

Beachten Sie, dass zwischen Collection und ArrayList eine weitere Abstraktionsebene besteht: die List Schnittstelle. In der Regel unterscheidet sich das Verwendungsmuster einer Liste stark von dem einer Karte, Menge oder Warteschlange. Die Art der Sammlung, die Sie für einen Job benötigen, wird normalerweise früh festgelegt und wird sich nicht ändern. Wenn Sie Ihre Variable als List deklarieren, wird diese Entscheidung klar und gibt ihren Kunden nützliche Informationen über den Vertrag, den diese Sammlung einhält. Collection OTOH ist normalerweise nicht sehr nützlich, um mehr als iterieren durch seine Elemente.

    
Péter Török 28.07.2010, 18:32
quelle
4

Es ist wahrscheinlich häufiger zu schreiben List<Something> myList = new ArrayList<Something>(); , um Collection zu verwenden. In der Regel sind einige Aspekte einer Liste von Bedeutung. Die Ungenauigkeit von Collection im Hinblick auf das Akzeptieren von doppelten Elementen, egal ob es sich um einen Satz oder eine Liste (oder was auch immer) handelt, kann ein Schmerz sein.

Abgesehen davon ist der Hauptzweck die Abstraktion oder die Unabhängigkeit der Implementierung. Interessiert es mich wirklich, wenn die Liste, die ich habe, ein ArrayList oder ein Vector ist? Wahrscheinlich nicht die meiste Zeit. Mein Code ist flexibler, wenn er die allgemeinste Schnittstelle verwendet, die ausdrückt, was das Objekt tun soll.

Das einfache Beispiel ist, dass Sie ein Programm schreiben, das alle ArrayList s verwendet und später mehrere Benutzer unterstützen muss. Um die Threadsicherheit zu erhöhen, müssen Sie alle ArrayList s in Vecto rs ändern. Wenn Sie Verweise auf den Typ ArrayList weitergegeben haben, müssen Sie jede Verwendung überall ändern. Wenn Sie Verweise auf den Typ List übergeben haben, müssen Sie nur die Orte ändern, an denen Sie sie erstellt haben.

Manchmal ist die implementierende Klasse möglicherweise nicht etwas, das Sie importieren und verwenden können oder wollen. Wenn Sie beispielsweise einen Persistenzprovider wie Hibernate verwenden, könnte die tatsächliche Klasse, die die Schnittstelle Set implementiert, eine hochspezialisierte benutzerdefinierte Implementierung sein, die für das Framework einzigartig ist, oder die alte Klasse HashSet , je nachdem, wie das Objekt erstellt wurde. Sie interessieren sich nicht für den Unterschied, es ist nur ein Set für Sie.

    
Affe 28.07.2010 18:36
quelle
3

Wenn Sie ArrayList deklarieren, würde ich niemals ArrayList als Typ auf der linken Seite verwenden. Programmieren Sie stattdessen auf der Benutzeroberfläche, sei es List oder < a href="http://java.sun.com/javase/6/docs/api/java/util/Collection.html"> Collection .

Beachten Sie, dass bei der Deklaration einer Methode als Collection eine List oder Set übergeben werden kann.

Als zusätzliche Randnotiz sollten Sie Generics verwenden.

Edit: Nachdem das gesagt wurde, führt Generics auch einige Gotchas ein.

List<Animal> könnte ein ArrayList<Animal> speichern, aber nicht ein ArrayList<Cat> . Sie benötigen List<? extends Animal> , um ArrayList<Cat> zu speichern.

    
Powerlord 28.07.2010 18:31
quelle
1

Zunächst einmal gibt es einen signifikanten Unterschied zwischen Vererbung und Schnittstellen. Eine kurze Reise zurück Geschichte: In einfachen alten C ++ konnten Sie von mehreren Klassen erben. Dies hat eine negative Konsequenz, wenn eine "Transformer" -Klasse von "Vehicle" und "Human" erbt, die beide eine Methode implementieren, die "MoveForward" genannt wird. Welche Funktion verwendet die Instanz, wenn Sie diese Methode in der Klasse "Transformer" aufrufen? die Implementierung "Mensch" oder "Fahrzeug"? Um dieses Problem zu lösen, werden Schnittstellen von Java, C #, ... eingeführt. Schnittstellen sind ein Vertrag zwischen Ihrer Klasse und etwas anderem. Sie verpflichten sich zur Funktionalität, aber der Vertrag implementiert KEINE Logik für Ihre Klasse (um das Problem Transformer.MoveForward zu verhindern).

Polymorphismus im Allgemeinen bedeutet, dass etwas auf verschiedene Arten erscheinen kann. Ein "Transformer" kann ein "Fahrzeug" und ein "Mensch" sein. Abhängig von Ihrer Sprache (ich verwende C #) können Sie unterschiedliche Verhaltensweisen für "MoveForward" implementieren, abhängig von dem Vertrag, den Sie erfüllen möchten.

Die Verwendung von Schnittstellen anstelle einer konkreten Implementierung hat mehrere Vorteile. Zunächst können Sie die Implementierung wechseln, ohne den Code zu ändern (Dependency Injection für Google Lookup;). Zweitens können Sie Ihren Code mit Test-Frameworks und Mock-Frameworks einfacher testen. Drittens ist es eine gute Praxis, den allgemeinsten Schnittstellen-Datenaustausch (Enumerator instad einer Liste) zu verwenden, wenn Sie nur über die Werte interagieren möchten.

Ich hoffe, das hilft ein wenig, die Vorteile von Schnittstellen zu verstehen.

    
ThomasMentzel 28.07.2010 18:47
quelle
1

Der Typ, den Sie in einer lokalen Variablendeklaration verwenden (wie in Ihrer ArrayList Beispiel) ist normalerweise nicht so wichtig. Alles, was Sie sicherstellen müssen, ist dass der Typ von myList (das Wort links von dem Namen 'myList') hat um spezifischer als der Typ eines beliebigen Methodenparameters zu sein meine Liste.

Überlegen Sie:

%Vor%

Ich hätte die Art von "Wörtern" ersetzen können, um nur List zu sein. Es tut es nicht machen einen Unterschied für die Lesbarkeit oder das Verhalten meines Programms. Ich konnte "Worte" jedoch nicht als Objekt definieren. Das ist zu allgemein.

Wenn Sie eine öffentliche Methode definieren, sollten Sie angeben sorgfältige Berücksichtigung der Arten der Parameter der Methode, da Das hat direkte Auswirkungen darauf, was der Anrufer weitergeben kann. Wenn ich definiert habe anders sortieren:

%Vor%

Die Definition von sort ist jetzt sehr restriktiv. Im ersten Beispiel Die sort-Methode erlaubt jedes Objekt als Parameter, so lange wie es ist implementiert die Sammlung. Im zweiten Beispiel erlaubt sort nur a LinkedList, akzeptiert es nichts anderes (ArrayLists, HashSets, TreeSets und viele andere). Die Szenarien, in denen die Sortiermethode ausgeführt werden kann verwendet werden sind jetzt ziemlich begrenzt. Dies könnte aus gutem Grund sein; das Die Implementierung von sort kann sich auf ein Feature der LinkedList stützen Datenstruktur. Es ist nur schlecht, diese Art zu definieren, wenn Leute benutzen Dieser Code möchte einen Sortieralgorithmus, der für andere Dinge als LinkedLists.

Eine der wichtigsten Fähigkeiten beim Schreiben von Java-Bibliotheken ist die Entscheidung über die Typen von Methodenparametern. Wie allgemein willst du sein?

    
Andy 28.07.2010 21:22
quelle
1

Nun, eine Arraylist hat eine dynamische Größe. Die Sammlung hat keine Überprüfung der Kompilierzeit, sie muss umgewandelt werden. Eine Sammlung enthält nur Objekte als Referenz. Sie können sich eine Sammlung als "Tasche" vorstellen. Und Manipulation kann über das gesamte Objekt durchgeführt werden. Ich bin mir auch sicher, dass die Suchzeit für eine Sammlung im Vergleich zu einer ArrayList kurz ist, aber nicht positiv. ArrayLists haben mehr Funktionalität und Methoden, die aufgerufen werden können.

    
CS Gamer 30.11.2012 17:25
quelle
0

Indem Sie myList als Collection deklarieren und verwenden, verbergen Sie die von Ihnen getroffene Implementierung (in diesem Fall wird sie als ArrayList dargestellt). Im Allgemeinen bedeutet dies, dass alle Dinge, die von Ihrem Code abhängen, nur darauf beruhen, dass sich myList als Collection verhält und nicht als ArrayList. Auf diese Weise, wenn Sie entscheiden, es später als etwas anderes darzustellen (ein Set? Eine verknüpfte Liste?), Aus welchem ​​Grund auch immer, brechen Sie nichts anderes.

    
Gian 28.07.2010 18:27
quelle
0

Collection ist ein Supertyp von ArrayList . Wenn Sie nur die Funktionalität von Collection benötigen, ist es eine gute Übung, da Sie explizit angeben, welche Funktionalität Sie in der Deklaration der Variablen brauchen . Dass du ein ArrayList in der Initialisierung auswählst, ist irrelevant (obwohl eine gute Standardwahl); Die Erklärung, dass es ein Collection ist, sagt Ihnen und jedem zukünftigen Programmierer genau, welchen Vertrag Sie interessieren.

    
Hank Gay 28.07.2010 18:27
quelle

Tags und Links