Mir wurde gesagt, dass die Programmierung von Schnittstellen für lokale Variablen nutzlos ist und nicht getan werden sollte, da dies nur die Leistung beeinträchtigt und keinen Nutzen bringt.
%Vor%statt
%Vor%Ich habe den Eindruck, dass der Performance-Hit vernachlässigbar ist, aber zugegebenermaßen gibt es nicht viel zu gewinnen, wenn man die List-Semantik von ArrayList verwendet. Gibt es starke Gründe, in die eine oder andere Richtung zu gehen?
Nehmen Sie diese Klasse zum Beispiel:
%Vor%Es kompiliert sich dazu:
%Vor%Während dieser Klasse:
%Vor%kompiliert sich dazu:
%Vor% Sie werden sehen, dass der einzige Unterschied darin besteht, dass der erste (mit ArrayList
) einen Aufruf an invokevirtual
und der andere (mit List
verwendet) invokeinterface
aufruft. invokeinterface
ist tatsächlich ein Haar, das langsamer ist als invokevirtual
(~ 38% nach dieser Typ ). Dies ist offensichtlich aufgrund von Optimierungen, die die JVM beim Durchsuchen der virtuellen Methodentabellen einer Klasse anhand der Methodentabellen einer Schnittstelle durchführen kann. Was Sie sagen, ist tatsächlich wahr. Schnittstellenaufrufe sind langsamer als konkrete Klassenaufrufe.
Allerdings müssen Sie überlegen, über welche Geschwindigkeit wir sprechen. Bei 100.000.000 Aufrufen betrug der tatsächliche Unterschied 0,03 Sekunden. Sie müssen also eine Tonne von Aufrufen haben, um tatsächlich eine signifikante Verringerung der Geschwindigkeit zu haben.
Auf der anderen Seite, wie @ChinBoon darauf hinweist, macht es das Programmieren für eine Schnittstelle wesentlich einfacher für diejenigen, die Ihren Code benutzen, besonders wenn Ihr Code eine Sorte List
zurückgibt. In den meisten Fällen überwiegt die Einfachheit der Kodierung far die relativen Leistungsausgaben.
Nach dem Lesen von @ MattQuigleys Kommentar hinzugefügt und auf der Heimfahrt nachgedacht
Was das alles bedeutet, ist, dass Sie sich nicht zu viel Sorgen machen sollten. Jede Leistungssteigerung oder Strafe ist wahrscheinlich sehr klein.
Beachten Sie, dass die Verwendung der Schnittstelle für Ihre Rückgabetypen und Ihre Parameter für Methoden eine sehr gute Idee ist. Damit können Sie und jeder, der Ihren Code verwendet, die Implementierung von List
nutzen, die am besten zu Ihren Anforderungen passt. Mein Beispiel zeigt auch, dass Sie, wenn Sie eine Methode verwenden, die 99% der Zeit List
zurückgibt, besser nicht besser in eine konkrete Klasse umwandeln können, nur um eine Leistungssteigerung zu erzielen. Die Zeit, die es dauert, um zu wirken, wird wahrscheinlich den Gewinn in der Leistung überwiegen.
Dieses Beispiel zeigt auch, dass Sie für eine lokale Variable in der Tat besser eine konkrete Klasse als eine Schnittstelle verwenden. Wenn Sie nur Methoden für List
verwenden, können Sie implementierende Klassen ohne Nebenwirkungen deaktivieren. Außerdem hätten Sie Zugriff auf die implementierungsspezifischen Methoden, falls Sie diese benötigen. Außerdem gibt es einen kleinen Leistungsschub.
tl; dr
Verwenden Sie immer Schnittstellen für Rückgabetypen und Parameter für Methoden. Es ist eine gute Idee, konkrete Klassen für lokale Variablen zu verwenden. Es führt zu geringfügigen Leistungssteigerungen und es entstehen keine Kosten für den Umstieg auf Implementierungen, wenn sich die einzigen Methoden, die Sie verwenden, auf der Schnittstelle befinden. Am Ende sollten Sie sich nicht zu viele Gedanken darüber machen. (Außer der Rückgabetypen und Parameter Sache. Das ist wichtig.)
Gilt die beste Vorgehensweise bei der Programmierung von Schnittstellen für lokale Variablen?
Auch wenn der Gültigkeitsbereich einer solchen Variable kleiner ist als der Bereich einer Elementvariablen, die meisten das Vorteile zum Codieren von Schnittstellen, wenn es um Elementvariablen geht, gilt auch für lokale Variablen.
Wenn Sie ArrayList-spezifische Methoden nicht benötigen, suchen Sie nach einer Liste.
Ich habe den Eindruck, dass der Performance-Hit vernachlässigbar ist, aber zugegebenermaßen gibt es nicht viel zu gewinnen, wenn man die List-Semantik von ArrayList verwendet
Ich habe noch nie gehört, dass Aufrufe von Interface-Methoden langsamer sind als das Aufrufen von Methoden für einen Klassentyp.
Die Verwendung von ArrayList
anstelle von List
als statischer Typ klingt für mich wie eine vorzeitige Optimierung. Wie üblich, bevorzugen Sie Lesbarkeit und Wartbarkeit gegenüber Optimierungen, bis Sie Ihr Programm als Ganzes profiliert haben.
TLDR: Methodenaufrufe sind an Schnittstellen / abstrakten Klassen langsamer, und es gibt praktisch keine Hindernisse dafür, die Implementierung einer lokalen Variablen zu einem späteren Zeitpunkt zu ändern macht die meisten Argumente zu einem strittigen Punkt.
Hier gibt es viele Antworten, die blind sagen, lokale Variablen als Schnittstellen zu deklarieren, ohne zu verstehen warum. Zuallererst ist der Methodenaufruf langsamer - etwa 3x, wie ich mich in Tests erinnere. Die Methode add
im ersten Codeblock ist dreimal so langsam wie die zweite. Sie können dies selbst mit einem einfachen Test testen, der die verstrichene Zeit in einer for-Schleife misst.
Zweitens geht es um lokale Variablen, nicht um objektorientierte Entwurfsprinzipien von Schnittstellen im Allgemeinen. Es gibt gute OO-Gründe, dass eine öffentliche Klassenmethode eine Schnittstelle oder abstrakte Klasse (List) anstelle der Implementierung (ArrayList) zurückgeben würde. Sie können über solche Gründe woanders nachlesen, aber diese Frage ist nicht - es geht um lokale Variablen. 99.999% Male werden Sie niemals die Implementierung dieser lokalen Variablen von ArrayList
in Vector
ändern. In den 0,001% -Zeiten, die Sie tatsächlich tun, gibt es jedoch keine Hindernisse - Sie kopieren einfach das Wort Vector über das Wort ArrayList und Sie sind es erledigt. Jeder scheint zu denken, dass eine solche Veränderung schwierig ist. Es ist nicht.
Drittens ist ein LinkedList
nicht dasselbe wie ein ArrayList
. Sie wählen das eine oder das andere aus einem bestimmten Grund (Zeit, die für den Zugriff / das Hinzufügen / Einfügen / Löschen benötigt wird). Die Angabe als ArrayList
ist eine Bestätigung, die Sie darüber informiert, dass diese lokale Variable für einen schnellen Direktzugriff gedacht ist. Das Argument, dass es sich um eine vorzeitige Optimierung handelt, ist albern - es wird auf die eine oder andere Weise optimiert, sobald es instanziiert wird.
Verwenden Sie den abstraktesten Typ, mit dem Sie die Aufgabe erledigen können. Wenn Sie nur List
benötigen, verwenden Sie es. Wenn Sie den Typ auf etwas konkreteres beschränken müssen, verwenden Sie stattdessen diesen Typ. Zum Beispiel wäre in einigen Fällen die Verwendung von List
zu konkret und die Verwendung von Collection
wäre bevorzugt. Als ein weiteres Beispiel könnte jemand in einigen Situationen eine ConcurrentMap
anstelle einer normalen Map
benötigen.
Insbesondere, wenn die Methode die Liste zurückgibt, hätte die Codierung an der Schnittstelle Ihnen geholfen, wenn Sie eines Tages die Implementierung in eine verknüpfte Liste ändern müssten. Und das ist ein Vorteil, Sie müssten die Methode nicht ändern, um eine verknüpfte Liste oder eine Arraylist zurückzugeben.
Hier ist ein Vorschlag: Erklären Sie die Liste als endgültig, aber mit der Schnittstelle.
%Vor%Wenn ich raten müsste (und ich bin kein Experte für den Java-Compiler selbst), aber die Variable endgültig machen, sollte der Compiler die invokeschnittstelle zugunsten von invokevirtual entfernen können, da er den Typ kennt wird sich nicht ändern, sobald die Variable deklariert ist.
Ja @ Matthew, ist viel besser die besten Praktiken mit
%Vor%, weil Sie die Methoden ArrayList-Klasse und List-Klasse verwenden können. Ich hoffe dir zu helfen.
Tags und Links java generics interface collections