For-each ist keine neue Syntax, sondern Syntaxzucker für Java. Zur Kompilierungszeit konvertiert der Compiler diesen Code in eine Iterator-Implementierung und kompiliert ihn in Bytecode. Wir können den folgenden kompilierten Code dekompilieren, indem wir den Befehl javap-verbose-Testforeach
ausführen: javap-verbose-Testforeach
反编译以下编译代码:
public class TestForeach { List<Integer> integers; public void testForeach(){ for(Integer i : integers){ } } }
获得的详细字节码如下:
public void testForeach(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=3, args_size=1 0: aload_0 1: getfield #2 // Field integers:Ljava/util/List; 4: invokeinterface #3, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 9: astore_1 10: aload_1 11: invokeinterface #4, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq 32 19: aload_1 20: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 25: checkcast #6 // class java/lang/Integer 28: astore_2 29: goto 10 32: return LineNumberTable: line 11: 0 line 13: 29 line 14: 32 LocalVariableTable: Start Length Slot Name Signature 29 0 2 i Ljava/lang/Integer; 0 33 0 this Ltest/TestForeach; }
此字节码的一般含义是使用getfileld
命令来获取integers
变量并且调用List.iterator
来获取迭代器实例和调用iterator.hasNext
。如果返回true
,调用iterator.next
public class ForLoopTest { public static void main(String[] args) { List<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < 10000000; i++) { arrayList.add(i); } long arrayListStartTime = System.currentTimeMillis(); for (int i = 0; i < arrayList.size(); i++) { arrayList.get(i); } long arrayListCost =System.currentTimeMillis()-arrayListStartTime; System.out.println("ArrayList for loop traversal cost: "+ arrayListCost); long arrayListForeachStartTime = System.currentTimeMillis(); for (Integer integer : arrayList) { } long arrayListForeachCost =System.currentTimeMillis()-arrayListForeachStartTime; System.out.println("ArrayList foreach traversal cost: "+ arrayListForeachCost);Der erhaltene detaillierte Bytecode lautet wie folgt:
rrreee
Die allgemeine Bedeutung dieses Bytecodes ist die Verwendung von getfileld
, um die Variable integers
abzurufen und List.iterator
aufzurufen, um die Iteratorinstanz abzurufen und iterator.hasNext
aufzurufen. Wenn true
zurückgegeben wird, rufen Sie die Methode iterator.next
auf. Bitte beachten Sie, dass dies die Implementierungslogik des Iterators ist, der die Sammlung durchläuft. BenchmarkingJetzt testen wir die Verwendung der for-Loop-Methode und der for-each-Methode. rrreeeHier sind die Testergebnisse:
Wie Sie sehen können, sind die Ergebnisse offensichtlich. Die Verwendung der For-Schleifenmethode ist bei ArrayList effizienter als die For-Each-Methode.
Können wir sagen, dass die for-Schleife besser ist als die for-each?
Die Antwort ist nein. Im nächsten Benchmark ändern wir die ArrayList in eine LinkedList. Hier noch einmal die Testergebnisse.
Ursachenanalyse
Einige Anfänger fragen sich vielleicht, warum ArrayList die for-Schleifenmethode verwendet, um schneller zu durchlaufen, während LinkedList langsamer und sehr langsam ist?
Dies wird durch die Datenstrukturen ArrayList und LinkedList bestimmt.
ArrayList verwendet Arrays, um Elemente darunter zu speichern. Arrays sind zusammenhängende Speicherbereiche. Daten können über Indizes abgerufen werden. Die Zeitkomplexität beträgt O(1), also ist es schnell. Die unterste Ebene von LinkedList ist eine doppelt verknüpfte Liste. Verwenden Sie eine for-Schleife, um den Durchlauf zu implementieren, und zwar jedes Mal vom Kopfknoten der verknüpften Liste aus. Die Zeitkomplexität beträgt O(n*n).Das obige ist der detaillierte Inhalt vonVergleichende Analyse von For- und For-each-Anwendungen in Java-Schleifen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!