Switch-Anweisungen mit StringFä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 StringKonstanten in caseDeklarationen wird zur Kompilierungszeit nach einem Muster zu komplexerem Code erweitert. Der resultierende Code verwendet JVM-Anweisungen, die immer vorhanden waren.
A switchmit StringFä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 ifAnweisung, 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 switchfinden 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 tableswitchBefehl.
Wenn die Konstanten spärlich sind, wird eine binäre Suche nach dem richtigen Fall durchgeführt - der lookupswitchAnweisung.
Beim Entzuckern switchvon StringObjekten werden wahrscheinlich beide Anweisungen verwendet. Das lookupswitchist 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 tableswitchAllgemeinen 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 enumkönnte sich ein StringSchalter annähern . Dies verwendet die statischevalueOf Methode, die vom Compiler für jeden enumTyp generiert wird . Zum Beispiel:
Pill p = Pill.valueOf(str);
switch(p) {
case RED: pop(); break;
case BLUE: push(); break;
}