2012-03-24 15 views
115

Mögliche Duplizieren:
Why should the interface for a Java class be prefered?Polymorphie: Warum "List list = new ArrayList" anstelle von "ArrayList list = new ArrayList" verwenden?

Wann sollte ich

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

ArrayList erbt von List verwenden, so dass, wenn einige Features in ArrayList sind nicht in List ich dann werden einige der Funktionen vonverloren haben, richtig? Und der Compiler bemerkt einen Fehler beim Versuch, auf diese Methoden zuzugreifen?

+0

Oh. Es tut mir Leid. weil ich zu 'object' wechsel, also vergesse ich es. – hqt

+6

@duffymo - Diese Frage fragt, warum 'neue Liste ()' nicht funktioniert. Es ist eine ganz andere Frage. –

+2

Es ist keine doppelte Frage. Das mögliche Duplikat hat eine allgemeine Frage, aber ein bestimmtes Detail. Ich finde diese Frage in Titel ist relevanter/synchron zu dem, was tatsächlich gefragt wird. – Dexters

Antwort

205

Der Hauptgrund, warum Sie dies tun, ist, Ihren Code von einer bestimmten Implementierung der Schnittstelle zu entkoppeln. Wenn Sie Ihren Code wie folgt schreiben:

List list = new ArrayList(); 

der Rest des Codes weiß nur, dass die Daten vom Typ List, was bevorzugt ist, weil es Ihnen zwischen verschiedenen Implementierungen der List Schnittstelle mit Leichtigkeit zu wechseln.

Zum Beispiel sagen Sie, dass Sie eine ziemlich große 3rd-Party-Bibliothek geschrieben haben und sagen, dass Sie sich entschieden haben, den Kern Ihrer Bibliothek mit einem LinkedList zu implementieren.Wenn Ihre Bibliothek stark auf den Zugriff auf Elemente in diesen Listen angewiesen ist, werden Sie feststellen, dass Sie eine schlechte Designentscheidung getroffen haben. Sie werden feststellen, dass Sie eine ArrayList (die O (1) Zugriffszeit gibt) anstelle einer LinkedList (die O (n) Zugriffszeit gibt) verwendet haben sollte. Vorausgesetzt, Sie haben an einer Schnittstelle programmiert, ist eine solche Änderung einfach. Sie würden einfach die Instanz von List von ändern,

List list = new LinkedList(); 

zu

List list = new ArrayList(); 

und Sie wissen, dass dies funktionieren wird, weil Sie Ihren Code geschrieben haben, den Vertrag durch die List Schnittstelle zu folgen.

Wenn Sie andererseits den Kern Ihrer Bibliothek mit LinkedList list = new LinkedList() implementiert haben, wäre eine solche Änderung nicht so einfach, da es keine Garantie dafür gibt, dass der Rest Ihres Codes keine Methoden verwendet spezifisch für die LinkedList Klasse.

Alles in allem ist die Wahl einfach eine Frage des Designs ... aber diese Art von Design ist sehr wichtig (besonders bei großen Projekten), da Sie später implementierungsspezifische Änderungen vornehmen können, ohne zu brechen bestehender Code.

+4

klare Erklärung. :) – coder247

+44

Viele Leute erwähnen nicht, dass es völlig akzeptabel ist, es als lokale Variable über ArrayList list = new ArrayList() zu instanziieren. Es ist nur von Vorteil, die List-Schnittstelle in der Methodensignatur oder als Typ einer Variablen auf Klassenebene zu verwenden. Wen kümmert es, wenn Sie später zurückgehen und die lokale Methodendeklaration ändern müssen? Der ganze Vorteil ergibt sich, wenn eine Liste anderen Methoden oder Bibliotheken usw. ausgesetzt wird. – GreenieMeanie

+5

Das stimmt, danke, dass Sie darauf hingewiesen haben. In der Tat, wenn ich jetzt darüber nachdenke, wäre es wahrscheinlich für mich sinnvoller gewesen, ein Beispiel aus der Sicht eines Kunden und nicht des Programmierers selbst zu geben. In beiden Fällen ist es bei der Verwendung von "List list = new ArrayList()" darauf zu achten, dass der vorhandene Code nicht verletzt wird. –

63

Dies wird Programmierung zu Schnittstelle genannt. Dies ist hilfreich, wenn Sie in Zukunft zu einer anderen Implementierung von List wechseln möchten. Wenn Sie einige Methoden in ArrayList möchten, dann müssten Sie zu der Implementierung programmieren, die ArrayList a = new ArrayList() ist.

6

Dies ermöglicht es Ihnen, so etwas wie zu schreiben:

void doSomething() { 
    List<String>list = new ArrayList<String>(); 
    //do something 
} 

Später, möchten Sie vielleicht, es zu ändern:

void doSomething() { 
    List<String>list = new LinkedList<String>(); 
    //do something 
} 

, ohne den Rest des Verfahrens zu ändern.

Wenn Sie jedoch ein CopyOnWriteArrayList zum Beispiel verwenden möchten, würden Sie es als solche deklarieren müssen und nicht als Liste , wenn Sie seine zusätzliche Methoden (addIfAbsent zum Beispiel) verwenden wollte:

void doSomething() { 
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>(); 
    //do something, for example: 
    list.addIfAbsent("abc"); 
} 
+1

Gemäß dem @GreenieMeanie-Kommentar der akzeptierten Antwort spielt diese Änderung keine Rolle, da es sich um eine lokale Variable handelt. – Ram

5

Ich benutze diese Konstruktion immer dann, wenn ich dem Problem keine Komplexität hinzufügen möchte. Es ist nur eine Liste, keine Notwendigkeit zu sagen, welche Art von Liste es ist, da es für das Problem keine Rolle spielt. Ich benutze für die meisten meiner Lösungen häufig Collection, da am Ende der meiste Rest, für den Rest der Software, der Inhalt wichtig ist und ich der Sammlung keine neuen Objekte hinzufügen möchte .

Außerdem verwenden Sie diese Konstruktion, wenn Sie denken, dass Sie die Implementierung der Liste ändern möchten, die Sie verwenden. Nehmen wir an, Sie verwenden die Konstruktion mit einer ArrayList, und Ihr Problem war nicht Thread-sicher. Jetzt möchten Sie es threadsicher machen, und für einen Teil Ihrer Lösung ändern Sie beispielsweise den Vektor. Wie für die anderen Verwendungen dieser Liste ist es egal, ob es eine AraryList oder ein Vector ist, nur eine Liste, keine neuen Modifikationen werden benötigt.

2

Im Allgemeinen möchten Sie gegen eine Schnittstelle programmieren. So können Sie die Implementierung jederzeit austauschen. Dies ist besonders nützlich, wenn Sie eine Implementierung erhalten, die Sie nicht kennen.

Es gibt jedoch bestimmte Situationen, in denen Sie die konkrete Implementierung bevorzugen. Zum Beispiel beim Serialisieren in GWT.

17

Dies ist auch hilfreich, wenn eine öffentliche Schnittstelle verfügbar gemacht wird. Wenn Sie eine Methode wie diese haben,

public ArrayList getList(); 

Dann entscheiden Sie, es zu ändern,

public LinkedList getList(); 

Wer ArrayList list = yourClass.getList() tat müssen ihren Code ändern. Auf der anderen Seite, wenn Sie dies tun,

public List getList(); 

Ändern der Implementierung ändert nichts für die Benutzer Ihrer API.

+0

yourClass.getList() ich denke, ist am praktischsten Anwendungsfall ich bin gestoßen. Vielen Dank :) –

4

Ich denke, der Kern Ihrer Frage ist, warum zu program to an interface, not to an implementation

Ganz einfach, weil eine Schnittstelle gibt Ihnen mehr Abstraktion und macht den Code flexibler und widerstandsfähig gegenüber Veränderungen, weil Sie verschiedene Implementierungen derselben verwenden können Schnittstelle (in diesem Fall möchten Sie vielleicht Ihre List-Implementierung in eine LinkedList anstelle einer ArrayList ändern), ohne ihren Client zu ändern.

10

Ich denke @ Tatzis Antwort ist meistens richtig (Programmierung auf eine Schnittstelle und nicht auf eine Implementierung). Jedoch, durch Programmierung der Schnittstelle verlieren Sie keine Funktionalität. Lassen Sie mich erklären.

Wenn Sie Ihre Variable als List<type> list = new ArrayList<type> deklarieren verlieren Sie nicht wirklich alle Funktionalität der ArrayList.Alles, was Sie tun müssen, ist, Ihre list auf ArrayList zu werfen. Hier ein Beispiel:

List<String> list = new ArrayList<String>(); 
((ArrayList<String>) list).ensureCapacity(19); 

Letztendlich denke ich tsatiz richtig ist, wie wenn Sie an einem Arraylist gegossen sind Sie nicht mehr Codierung an einer Schnittstelle. Es ist jedoch immer noch eine gute Vorgehensweise, zunächst eine Schnittstelle zu programmieren und, wenn es später notwendig wird, eine Implementierung zu codieren.

Hoffe, dass hilft!

+0

Dieser ist sehr einfach und klar. – CopsOnRoad

Verwandte Themen