2013-06-07 9 views
10

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?

+6

akceptuje także struny i wyliczenia od JDK 1.7. –

+2

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

+0

@MadProgrammer Cóż, możesz stworzyć dowolny obiekt i użyć równa się, aby dopasować do każdego przypadku, tak myślę. – Thihara

Odpowiedz

16

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.

+3

Z ciekawości: A teraz, w jaki sposób obsługuje ona struny? czy możesz podać jakiś pomysł? –

+1

@Baadshah: Bardzo dobre pytanie! Zaktualizowałem, aby rozwiązać ten problem. –

+0

Dziękuję Ci Crowder.Assome wyjaśnienie dla prostego komentarza. –

1

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(); 
} 

}