it-swarm.com.de

Polymorphismus: Warum "List list = new ArrayList" anstelle von "ArrayList list = new ArrayList" verwenden?

Mögliches Duplikat:
Warum sollte die Schnittstelle für eine Java Klasse bevorzugt werden?

Wann soll ich verwenden

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

ArrayList erbt von List. Wenn also einige Funktionen in ArrayList nicht in List enthalten sind, habe ich einige der Funktionen von ArrayList, richtig? Und der Compiler wird einen Fehler bemerken, wenn er versucht, auf diese Methoden zuzugreifen?

136
hqt

Der Hauptgrund dafür ist, Ihren Code von einer bestimmten Implementierung der Schnittstelle zu entkoppeln. Wenn Sie Ihren Code so schreiben:

List list = new ArrayList();  

der Rest Ihres Codes weiß nur, dass die Daten vom Typ List sind. Dies ist vorzuziehen, da Sie so problemlos zwischen verschiedenen Implementierungen der Schnittstelle List wechseln können.

Angenommen, Sie haben eine relativ große Bibliothek von Drittanbietern geschrieben, und Sie haben beschlossen, 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 schließlich feststellen, dass Sie eine schlechte Entwurfsentscheidung getroffen haben. Sie werden feststellen, dass Sie ein ArrayList (das die Zugriffszeit O(1) angibt) anstelle eines LinkedList (das die Zugriffszeit O(n) Zugriffszeit). Vorausgesetzt, Sie haben eine 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, um dem Vertrag zu folgen, der von der Schnittstelle List bereitgestellt wird.

Wenn Sie dagegen den Kern Ihrer Bibliothek mit LinkedList list = new LinkedList() implementiert hätten, wäre eine solche Änderung nicht so einfach, da nicht garantiert werden kann, dass der Rest Ihres Codes keine Verwendung findet von Methoden, die für die Klasse LinkedList spezifisch sind.

Alles in allem ist die Wahl einfach eine Frage des Designs ... aber diese Art des Designs ist sehr wichtig (insbesondere bei der Arbeit an großen Projekten), da Sie später implementierungsspezifische Änderungen vornehmen können, ohne den vorhandenen Code zu beschädigen.

242
Alex Lockwood

Dies nennt man Programmierung zur Schnittstelle. Dies ist hilfreich, wenn Sie in Zukunft zu einer anderen Implementierung von List wechseln möchten. Wenn Sie einige Methoden in ArrayList verwenden möchten, müssen Sie die Implementierung ArrayList a = new ArrayList() programmieren.

67
tsatiz

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

public ArrayList getList();

Dann beschließen Sie, es zu ändern,

public LinkedList getList();

Jeder, der ArrayList list = yourClass.getList() ausgeführt hat, muss seinen Code ändern. Auf der anderen Seite, wenn Sie es tun,

public List getList();

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

21
Brendan Long

Ich denke, die Antwort von @ tsatiz ist größtenteils richtig (Programmierung auf eine Schnittstelle anstatt auf eine Implementierung). Allerdings durch die Programmierung auf die Schnittstelle verlieren Sie keine Funktionalität. Lassen Sie mich erklären.

Wenn Sie Ihre Variable als List<type> list = new ArrayList<type> Deklarieren</ code> Sie verlieren keine Funktionalität der ArrayList. Alles, was Sie tun müssen, ist, Ihr list in ein ArrayList umzuwandeln. Hier ist ein Beispiel:

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

Letztendlich denke ich, dass tsatiz korrekt ist, da Sie nach dem Umwandeln in eine ArrayList nicht mehr in eine Schnittstelle codieren. Es ist jedoch immer noch eine gute Praxis, zunächst eine Schnittstelle zu codieren und, falls dies später erforderlich wird, eine Implementierung zu codieren, falls dies erforderlich ist.

Hoffentlich hilft das!

10
SecondSun24

Auf diese Weise können Sie Folgendes schreiben:

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

Später möchten Sie möglicherweise Folgendes ändern:

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

ohne den Rest der Methode zu ändern.

Wenn Sie jedoch zum Beispiel ein CopyOnWriteArrayList verwenden möchten, müssen Sie es als solches deklarieren und nicht als List wenn Sie seine zusätzlichen Methoden verwenden möchten (zum Beispiel addIfAbsent) ):

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

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

Einfach, weil eine Schnittstelle Ihnen mehr Abstraktion verleiht und den Code flexibler und widerstandsfähiger für Änderungen macht, weil Sie verschiedene Implementierungen derselben Schnittstelle verwenden können (in diesem Fall möchten Sie möglicherweise Ihre List-Implementierung in eine LinkedList anstelle einer ArrayList ändern). ohne den Client zu wechseln.

5
Mouna Cheikhna

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 Collection oft für die meisten meiner Lösungen, und am Ende ist meistens für den Rest der Software der Inhalt von Bedeutung, und ich möchte der Collection keine neuen Objekte hinzufügen .

Darüber hinaus verwenden Sie diese Konstruktion, wenn Sie glauben, dass Sie die Implementierung der von Ihnen verwendeten Liste ändern möchten. Angenommen, Sie haben die Konstruktion mit einer ArrayList verwendet und Ihr Problem war nicht threadsicher. Jetzt möchten Sie es threadsicher machen und für einen Teil Ihrer Lösung beispielsweise auf die Verwendung eines Vektors umstellen. Da für die anderen Verwendungen dieser Liste keine Rolle spielt, ob es sich um eine AraryList oder einen Vector handelt, sondern nur um eine Liste, sind keine neuen Änderungen erforderlich.

5
SHiRKiT

Im Allgemeinen möchten Sie gegen eine Schnittstelle programmieren. Auf diese Weise können Sie die Implementierung jederzeit austauschen. Dies ist sehr nützlich, insbesondere wenn Sie eine Implementierung bestanden haben, die Sie nicht kennen.

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

2
stefan bachert