Dlaczego instrukcja switch case w Javie przyjmuje tylko liczbę całkowitą, krótki, bajt i znak, a nie inne typy danych? Jakie mogą być korzyści? Proszę szczegółowo wyjaśnić.Dlaczego instrukcja rozdzielnicy w Javie działa w ten sposób?
Odpowiedz
Zwykle pytania dotyczące projektowania języka sprowadzają się do "ponieważ projektanci zdecydowali się to zrobić". To tylko kolejny z tych czasów.
Ale Java ma pewne pochodzenie w C, które zrobiło to samo, aw latach 80. decyzja ta została mi wyjaśniona, ponieważ wtedy kompilator mógł zamienić przełącznik w tabelę skoków: Zasadniczo każdy blok adresu kodu jest umieszczany w tabeli, a switch
staje się sprawdzaniem zakresu, po którym następuje przeglądanie tabeli (zazwyczaj indeksowanie do tablicy lub co najmniej połączonej listy tablic) za pomocą wartości, którą przekazujesz, aby uzyskać adres, a następnie przeskoczenie do tego adresu. Tylko liczby całkowite mają sens w tym scenariuszu. Pamiętaj, że komputery nie zawsze były tak szybkie, jak teraz. C został zaprojektowany na początku lat 70-tych w oparciu o pracę pod koniec lat 60-tych, kiedy komputery były znacznie wolniejsze.
Niektóre języki w tym samym składniowej tradycji jak Java i C, takie jak JavaScript, dokonać switch
tylko inny sposób pisania if...else/if...else
i nie ograniczają typu są sprawdzane do integralnych typów, być może dlatego, że są zaprojektowane w lata 90-te stały się realistyczną opcją. A może właśnie dlatego, że projektant JavaScript (Brendan Eich) wolał to w ten sposób.
Poniżej Baadshah pyta:
Z ciekawości: A teraz jak jej Strings wspierających ??? czy możesz podać jakiś pomysł?
Najpierw krok do tyłu i spojrzeć na sprawy int
:
num = Integer.parseInt(args[0]);
switch (num) {
case 1:
System.out.println("You used the special value one");
break;
case 42:
System.out.println("You used the special value forty-two");
break;
case 67:
System.out.println("You used the special value sixty-seven");
break;
default:
System.out.println("You used the a non-special value " + num);
break;
}
która produkuje kodu bajtowego tak:
19: iload_2 20: lookupswitch { // 3 1: 56 42: 67 67: 78 default: 89 } 56: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 59: ldc #9 // String You used the special value one 61: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 64: goto 114 67: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 70: ldc #11 // String You used the special value forty-two 72: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 75: goto 114 78: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 81: ldc #12 // String You used the special value sixty-seven 83: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 86: goto 114 89: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 92: new #13 // class java/lang/StringBuilder 95: dup 96: invokespecial #14 // Method java/lang/StringBuilder."":()V 99: ldc #15 // String You used the a non-special value 101: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 104: iload_2 105: invokevirtual #17 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 108: invokevirtual #18 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 111: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
Widzimy przeszukiwania tablicy na int
w akcji.
Jak to zrobić ze stringami? Cóż, jedną odpowiedzią byłoby po prostu przekształcenie switch
w strukturę . Ale zrobili coś więcej niż mądry: Wykorzystali hashcode zoptymalizować, a następnie wykorzystywane equals
celu ochrony przed zderzeniami:
switch (str) {
case "abc":
System.out.println("You used the special value 'abc'");
break;
case "def":
System.out.println("You used the special value 'def'");
break;
case "ghi":
System.out.println("You used the special value 'ghi'");
break;
default:
System.out.println("You used the a non-special value '" + str + "'");
break;
}
staje:
124: aload 4 126: invokevirtual #19 // Method java/lang/String.hashCode:()I 129: lookupswitch { // 3 96354: 164 99333: 180 102312: 196 default: 209 } 164: aload 4 166: ldc #20 // String abc 168: invokevirtual #21 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 171: ifeq 209 174: iconst_0 175: istore 5 177: goto 209 180: aload 4 182: ldc #22 // String def 184: invokevirtual #21 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 187: ifeq 209 190: iconst_1 191: istore 5 193: goto 209 196: aload 4 198: ldc #23 // String ghi 200: invokevirtual #21 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 203: ifeq 209 206: iconst_2 207: istore 5 209: iload 5 211: tableswitch { // 0 to 2 0: 236 1: 247 2: 258 default: 269 } 236: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 239: ldc #24 // String You used the special value 'abc' 241: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 244: goto 299 247: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 250: ldc #25 // String You used the special value 'def' 252: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 255: goto 299 258: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 261: ldc #26 // String You used the special value 'ghi' 263: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 266: goto 299 269: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 272: new #13 // class java/lang/StringBuilder 275: dup 276: invokespecial #14 // Method java/lang/StringBuilder."":()V 279: ldc #27 // String You used the a non-special value ' 281: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 284: aload_3 285: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 288: ldc #28 // String ' 290: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 293: invokevirtual #18 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 296: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
Zobacz, co zrobili tam? Obecnie jest to po prostu dwa switches
teraz: jeden, aby uzyskać unikalny numer dla każdego przypadku w oparciu o kod skrótu (ale podwójne sprawdzanie z equals
), a następnie drugi do wysłania.
Z ciekawości: A teraz, w jaki sposób obsługuje ona struny? czy możesz podać jakiś pomysł? –
@Baadshah: Bardzo dobre pytanie! Zaktualizowałem, aby rozwiązać ten problem. –
Dziękuję Ci Crowder.Assome wyjaśnienie dla prostego komentarza. –
Instrukcja switch JDK6 działa na char, byte, int pierwotnych typach danych i wyliczeniu. W JDK 7 zorientowali się, że plik java.lang.String jest także stałą i został dodany do listy typów danych obsługiwanych przez instrukcję switch.
Na przykład poniższy kod działa poprawnie w JDK7.
public static void OpenSource(String language)
{
switch (language) {
case "PERL":
System.out.println("PERL");
break;
case "Python":
System.out.println("Python");
break;
case "Ruby":
System.out.println("Ruby");
break;
case "PHP":
System.out.println("PHP");
break;
default:
throw new IllegalArgumentException();
}
}
akceptuje także struny i wyliczenia od JDK 1.7. –
Jest to wymaganie językowe. W Javie 7 obsługuje teraz 'String', a ponieważ wprowadzono' enum', obsługuje on również 'enum'. Pytanie naprawdę sprowadza się do tego, jak zdefiniowałbyś przypadek dla dowolnego obiektu? – MadProgrammer
@MadProgrammer Cóż, możesz stworzyć dowolny obiekt i użyć równa się, aby dopasować do każdego przypadku, tak myślę. – Thihara