Почему оператор case switch в Java принимает только целочисленные, короткие, байт и только символы, а не другие типы данных? Какая может быть польза? Пожалуйста, объясните подробно.
Почему оператор switchcase в Java работает так?
Ответ 1
Обычно вопросы дизайна языка сводятся к "потому, что дизайнеры решили это сделать". Это еще один пример того времени.
Но у Java есть некоторые истоки в C, которые сделали то же самое, и в 80 это решение было объяснено мне как потому, что тогда компилятор мог превратить коммутатор в таблицу перехода. В основном каждый блок кода-кода помещается в таблицу, а switch становится проверкой диапазона, за которой следует поиск таблицы (обычно индексируется в массив или по крайней мере связанный список массивов), используя значение, которое вы передаете, чтобы получить адрес, а затем переходите к этому адресу. Только целые числа имеют смысл в этом сценарии. Помните, что компьютеры не всегда были такими быстрыми, как сейчас. C был разработан в начале 70-х годов на основе работы в конце 60-х, когда компьютеры были намного медленнее.
Некоторые языки в той же синтаксической традиции, что и Java и C, такие как JavaScript, делают switch просто еще одним способом записи if...else/if...else и не ограничивают тип, проверяемый на интегральные типы, возможно, потому, что, будучи разработанным в 90-е годы это стало реалистичным вариантом. Или, может быть, только потому, что разработчик JavaScript (Брендан Эйх) предпочитал это именно так.
Ниже Baadshah спрашивает:
Из любопытства: Тогда теперь как его поддерживающие Струны??? не могли бы вы дать какую-то идею?
Сначала отпустите назад и посмотрите на случай 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;
}
Это создает байт-код следующим образом:
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
Мы можем увидеть поиск таблицы в int в действии.
Итак, как вы это делаете со строками? Ну, один ответ - просто превратить switch в структуру if...else if...else. Но они сделали что-то более умное: они использовали хэш-код для оптимизации, а затем использовали equals для защиты от коллизий:
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;
}
становится:
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
Посмотрите, что они там сделали? Это в основном два switches теперь: один, чтобы получить уникальный номер для каждого случая на основе хэш-кода (но дважды проверяя с помощью equals), а затем второй для отправки.
Ответ 2
Оператор switch JDK6 работал с char, байтом, int примитивными типами данных и перечислением. В JDK 7 они поняли, что java.lang.String также является константой и добавлен в список типов данных, поддерживаемых оператором switch.
Например, следующий код отлично работает в 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();
}
}