PMD würde einen Verstoß melden für:
ArrayList<Object> list = new ArrayList<Object>();
Die Verletzung lautete "Vermeiden Sie die Verwendung von Implementierungstypen wie 'ArrayList'; verwenden Sie stattdessen die Schnittstelle".
Die folgende Zeile würde den Verstoß korrigieren:
List<Object> list = new ArrayList<Object>();
Warum sollte letzteres mit List
statt verwendet werden ArrayList
?
java
collections
interface
jnancheta
quelle
quelle
Antworten:
Die Verwendung von Schnittstellen über konkreten Typen ist der Schlüssel für eine gute Kapselung und für die lose Kopplung Ihres Codes.
Es ist sogar eine gute Idee, diese Vorgehensweise beim Schreiben eigener APIs zu befolgen. Wenn Sie dies tun, werden Sie später feststellen, dass es einfacher ist, Ihrem Code Komponententests hinzuzufügen (mithilfe von Mocking-Techniken) und die zugrunde liegende Implementierung bei Bedarf in Zukunft zu ändern.
Hier ist ein guter Artikel zu diesem Thema.
Ich hoffe es hilft!
quelle
Dies wird bevorzugt, weil Sie Ihren Code von der Implementierung der Liste entkoppeln. Mit der Schnittstelle können Sie die Implementierung, in diesem Fall ArrayList, problemlos in eine andere Listenimplementierung ändern, ohne den Rest des Codes zu ändern, solange nur die in List definierten Methoden verwendet werden.
quelle
Im Allgemeinen stimme ich zu, dass die Entkopplung der Schnittstelle von der Implementierung eine gute Sache ist und die Wartung Ihres Codes erleichtert.
Es gibt jedoch Ausnahmen, die Sie berücksichtigen müssen. Durch den Zugriff auf Objekte über Schnittstellen wird eine zusätzliche Indirektionsebene hinzugefügt, die Ihren Code langsamer macht.
Aus Interesse habe ich ein Experiment durchgeführt, bei dem zehn Milliarden sequenzielle Zugriffe auf eine ArrayList mit einer Länge von 1 Million generiert wurden. Auf meinem 2,4-GHz-MacBook dauerte der Zugriff auf die ArrayList über eine List-Oberfläche durchschnittlich 2,10 Sekunden, bei der Deklaration vom Typ ArrayList durchschnittlich 1,67 Sekunden.
Wenn Sie mit großen Listen arbeiten, die sich tief in einer inneren Schleife befinden oder häufig als Funktion bezeichnet werden, sollten Sie dies berücksichtigen.
quelle
ArrayList und LinkedList sind zwei Implementierungen einer Liste, bei der es sich um eine geordnete Sammlung von Elementen handelt. In logischer Hinsicht spielt es keine Rolle, ob Sie eine ArrayList oder eine LinkedList verwenden, daher sollten Sie den Typ nicht darauf beschränken.
Dies steht im Gegensatz zu "Sammlung" und "Liste", die unterschiedliche Dinge sind (Liste impliziert Sortieren, Sammlung nicht).
quelle
Es ist eine gute Praxis: Programm zur Schnittstelle statt zur Implementierung
Durch Ersetzen
ArrayList
durchList
können Sie dieList
Implementierung in Zukunft abhängig von Ihrem Geschäftsanwendungsfall wie folgt ändern .List<Object> list = new LinkedList<Object>(); /* Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations, and permits all elements (including null).*/
ODER
List<Object> list = new CopyOnWriteArrayList<Object>(); /* A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.*/
ODER
List<Object> list = new Stack<Object>(); /* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/
ODER
eine andere
List
spezifische Implementierung.List
Schnittstelle definiert Vertrag und spezifische Implementierung vonList
kann geändert werden. Auf diese Weise sind Schnittstelle und Implementierung lose miteinander verbunden.Verwandte SE-Frage:
Was bedeutet es, auf eine Schnittstelle zu programmieren?
quelle
Selbst für lokale Variablen hilft die Verwendung der Schnittstelle über der konkreten Klasse. Möglicherweise rufen Sie eine Methode auf, die sich außerhalb der Schnittstelle befindet, und es ist dann schwierig, die Implementierung der Liste bei Bedarf zu ändern. Es ist auch am besten, die am wenigsten spezifische Klasse oder Schnittstelle in einer Deklaration zu verwenden. Wenn die Reihenfolge der Elemente keine Rolle spielt, verwenden Sie eine Sammlung anstelle einer Liste. Das gibt Ihrem Code maximale Flexibilität.
quelle
Die Eigenschaften Ihrer Klassen / Schnittstellen sollten über Schnittstellen verfügbar gemacht werden, da Ihre Klassen unabhängig von der Implementierung einen Verhaltensvertrag erhalten.
Jedoch...
In lokalen Variablendeklarationen ist dies wenig sinnvoll:
public void someMethod() { List theList = new ArrayList(); //do stuff with the list }
Wenn es sich um eine lokale Variable handelt, verwenden Sie einfach den Typ. Es ist immer noch implizit auf die entsprechende Schnittstelle hochsetzbar, und Ihre Methoden sollten hoffentlich die Schnittstellentypen für ihre Argumente akzeptieren. Für lokale Variablen ist es jedoch absolut sinnvoll, den Implementierungstyp als Container zu verwenden, nur für den Fall, dass Sie die Implementierung benötigen. spezifische Funktionalität.
quelle
Im Allgemeinen ist es für Ihre Codezeile nicht sinnvoll, sich mit Schnittstellen zu beschäftigen. Aber wenn wir über APIs sprechen, gibt es einen wirklich guten Grund. Ich habe eine kleine Klasse
class Counter { static int sizeOf(List<?> items) { return items.size(); } }
In diesem Fall ist die Verwendung der Schnittstelle erforderlich. Weil ich die Größe jeder möglichen Implementierung einschließlich meiner eigenen Gewohnheit zählen möchte .
class MyList extends AbstractList<String>...
.quelle
Die Schnittstelle ist dem Endbenutzer zugänglich. Eine Klasse kann mehrere Schnittstellen implementieren. Benutzer, die einer bestimmten Schnittstelle ausgesetzt sind, haben Zugriff auf ein bestimmtes Verhalten, das in dieser bestimmten Schnittstelle definiert ist.
Eine Schnittstelle hat auch mehrere Implementierungen. Basierend auf dem Szenario arbeitet das System mit verschiedenen Szenarien (Implementierung der Schnittstelle).
Lassen Sie mich wissen, wenn Sie weitere Erklärungen benötigen.
quelle
Die Schnittstelle ist in der Debugger-Ansicht häufig besser dargestellt als die konkrete Klasse.
quelle