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?
Trả lời
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.
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? –
@Baadshah: Một câu hỏi rất hay! Tôi đã cập nhật để giải quyết nó. –
Cảm ơn bạn Crowder.Awsome giải thích cho một bình luận đơn giản. –
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();
}
}
Nó cũng chấp nhận Strings và Enums từ JDK 1.7. –
Đâ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
@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