2013-06-07 35 views
10

Tại sao câu lệnh trong trường hợp chuyển đổi trong Java chỉ lấy số nguyên, ngắn, byte và ký tự chứ không phải các kiểu dữ liệu khác? Điều gì có thể là lợi ích? Vui lòng giải thích chi tiết.Tại sao câu lệnh switchcase trong Java hoạt động như thế này?

+6

Nó cũng chấp nhận Strings và Enums từ JDK 1.7. –

+2

Đây là yêu cầu ngôn ngữ. Trong Java 7, bây giờ nó hỗ trợ 'String' và vì' enum' được giới thiệu, nó cũng hỗ trợ 'enum'. Câu hỏi thực sự đi xuống để làm thế nào bạn sẽ xác định một trường hợp cho một đối tượng tùy ý? – MadProgrammer

+0

@MadProgrammer Vâng, bạn có thể tạo một đối tượng tùy ý và sử dụng bằng để khớp với từng trường hợp tôi đoán. – Thihara

Trả lời

16

Thắc mắc thường gặp về thiết kế ngôn ngữ luôn "sôi nổi" bởi vì đó là cách các nhà thiết kế quyết định làm điều đó. " Đây chỉ là một trong những lần đó.

Nhưng Java có một số xuất xứ trong C, điều tương tự, và trong quyết định của 80 đã được giải thích cho tôi vì trình biên dịch có thể biến công tắc thành bảng nhảy: Về cơ bản, mỗi khối địa chỉ của mã được đặt trong một bảng và switch trở thành kiểm tra phạm vi tiếp theo là tra cứu bảng (thường là lập chỉ mục thành một mảng hoặc ít nhất là danh sách mảng được liên kết) bằng giá trị bạn chuyển vào để lấy địa chỉ và sau đó chuyển đến địa chỉ đó. Chỉ số nguyên hợp lý trong kịch bản đó. Hãy nhớ rằng các máy tính không phải lúc nào cũng nhanh như bây giờ. C được thiết kế vào đầu những năm 70 dựa trên công việc vào cuối những năm 60, khi máy tính chậm hơn nhiều.

Một số ngôn ngữ trong cùng cú pháp truyền thống như Java và C, chẳng hạn như JavaScript, làm cho switch chỉ là một cách viết if...else/if...else và không giới hạn các loại đang được kiểm tra để loại không thể thiếu, có lẽ bởi vì, được thiết kế theo những năm 90, đã trở thành một lựa chọn thực tế. Hoặc có lẽ chỉ vì nhà thiết kế JavaScript (Brendan Eich) ưa thích nó theo cách đó.


Dưới đây, Baadshah hỏi:

Ra khỏi tò mò: Sau đó, giờ làm thế nào Strings hỗ trợ của nó ??? bạn có thể đưa ra một số ý tưởng không?

Trước tiên, hãy lùi lại và nhìn vào trường hợp 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; 
    } 

Đó sản xuất bytecode như thế này:

 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

Chúng ta có thể thấy việc tra cứu bảng trên int trong hành động.

Vậy bạn làm điều đó bằng dây như thế nào? Vâng, một câu trả lời sẽ là chỉ cần biến switch thành cấu trúc if...else if...else. Nhưng họ đã làm một cái gì đó thông minh hơn rằng: Họ đã sử dụng hashcode để tối ưu hóa, và sau đó sử dụng equals để bảo vệ chống va chạm:

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

trở thành:

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

Xem những gì họ đã làm ở đó? Về cơ bản nó là hai switches bây giờ: Một để có được một số duy nhất cho mỗi trường hợp dựa trên mã băm (nhưng kiểm tra lại với equals), và sau đó là thứ hai để gửi đi.

+3

Hết sức tò mò: Sau đó, bây giờ làm thế nào hỗ trợ Strings của nó ??? bạn có thể đưa ra một số ý tưởng không? –

+1

@Baadshah: Một câu hỏi rất hay! Tôi đã cập nhật để giải quyết nó. –

+0

Cảm ơn bạn Crowder.Awsome giải thích cho một bình luận đơn giản. –

1

Tuyên bố chuyển đổi JDK6 hoạt động trên các loại dữ liệu nguyên gốc, char, byte và enum. Trong JDK 7, họ nhận ra rằng java.lang.String cũng là một hằng số và đã được thêm vào danh sách các kiểu dữ liệu được hỗ trợ bởi một câu lệnh switch.

Ví dụ: mã sau hoạt động tốt trong 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(); 
} 

}

Các vấn đề liên quan