Switch-Anweisungen mit String
Fällen wurden in Java SE 7 mindestens 16 Jahre nach ihrer ersten Anforderung implementiert . Ein klarer Grund für die Verzögerung wurde nicht angegeben, hatte aber wahrscheinlich mit der Leistung zu tun.
Implementierung in JDK 7
Die Funktion wurde jetzt javac
mit einem "Entzuckern" -Verfahren implementiert. Eine saubere Syntax auf hoher Ebene unter Verwendung von String
Konstanten in case
Deklarationen wird zur Kompilierungszeit nach einem Muster zu komplexerem Code erweitert. Der resultierende Code verwendet JVM-Anweisungen, die immer vorhanden waren.
A switch
mit String
Fällen wird während der Kompilierung in zwei Schalter übersetzt. Der erste ordnet jede Zeichenfolge einer eindeutigen Ganzzahl zu - ihrer Position im ursprünglichen Schalter. Dies erfolgt, indem zuerst der Hash-Code des Etiketts eingeschaltet wird. Der entsprechende Fall ist eine if
Anweisung, die die Zeichenfolgengleichheit testet. Wenn der Hash kollidiert, ist der Test eine Kaskadierung if-else-if
. Der zweite Schalter spiegelt dies im ursprünglichen Quellcode wider, ersetzt jedoch die Fallbezeichnungen durch die entsprechenden Positionen. Dieser zweistufige Prozess macht es einfach, die Flusskontrolle des ursprünglichen Schalters beizubehalten.
Schalter in der JVM
Weitere technische Informationen switch
finden Sie in der JVM-Spezifikation, in der die Zusammenstellung von switch-Anweisungen beschrieben wird. Kurz gesagt, es gibt zwei verschiedene JVM-Anweisungen, die für einen Switch verwendet werden können, abhängig von der Sparsamkeit der von den Fällen verwendeten Konstanten. Beide hängen von der Verwendung ganzzahliger Konstanten für jeden Fall ab, um eine effiziente Ausführung zu gewährleisten.
Wenn die Konstanten dicht sind, werden sie als Index (nach Subtraktion des niedrigsten Werts) in eine Tabelle mit Befehlszeigern verwendet - den tableswitch
Befehl.
Wenn die Konstanten spärlich sind, wird eine binäre Suche nach dem richtigen Fall durchgeführt - der lookupswitch
Anweisung.
Beim Entzuckern switch
von String
Objekten werden wahrscheinlich beide Anweisungen verwendet. Das lookupswitch
ist für den ersten Einschalt-Hash-Code geeignet, um die ursprüngliche Position des Gehäuses zu ermitteln. Die resultierende Ordnungszahl ist eine natürliche Anpassung für a tableswitch
.
Beide Anweisungen erfordern, dass die jedem Fall zugewiesenen Ganzzahlkonstanten zur Kompilierungszeit sortiert werden. Während zur Laufzeit die O(1)
Leistung von im tableswitch
Allgemeinen besser erscheint als die O(log(n))
Leistung von lookupswitch
, ist eine Analyse erforderlich, um festzustellen, ob die Tabelle dicht genug ist, um den Raum-Zeit-Kompromiss zu rechtfertigen. Bill Venners hat einen großartigen Artikel geschrieben , der dies ausführlicher behandelt, zusammen mit einem Blick unter die Haube auf andere Anweisungen zur Java-Flusskontrolle.
Vor JDK 7
Vor JDK 7 enum
könnte sich ein String
Schalter annähern . Dies verwendet die statischevalueOf
Methode, die vom Compiler für jeden enum
Typ generiert wird . Zum Beispiel:
Pill p = Pill.valueOf(str);
switch(p) {
case RED: pop(); break;
case BLUE: push(); break;
}