2013-06-07 2 views
10

Pourquoi l'instruction de casse de commutateur dans Java prend seulement entier, court, octet et caractère seulement et pas d'autres types de données? Quel pourrait être le bénéfice? S'il vous plaît expliquer en détail.Pourquoi l'instruction switchcase dans Java fonctionne comme ceci?

+6

Il accepte également des chaînes et énumérations depuis 1.7 JDK. –

+2

Ceci est une exigence de langue. Sous Java 7, il supporte maintenant 'String' et depuis que' enum' a été introduit, il supporte aussi 'enum'. La question se résume à comment définiriez-vous un cas pour un objet arbitraire? – MadProgrammer

+0

@MadProgrammer Eh bien, vous pouvez créer un objet arbitraire et utiliser égal pour correspondre à chaque cas je suppose. – Thihara

Répondre

16

Habituellement, les questions de conception de langage se résument à "parce que c'est ainsi que les concepteurs ont décidé de le faire." C'est juste un autre de ces moments. Mais Java a quelques origines en C, qui ont fait la même chose, et dans les années 80 cette décision m'a été expliquée comme étant parce que le compilateur pouvait alors transformer le commutateur en une table de saut: Fondamentalement, chaque bloc d'adresse de code est placé dans une table et le switch devient une vérification de plage suivie d'une recherche de table (généralement indexée dans un tableau ou au moins une liste chaînée de tableaux) en utilisant la valeur que vous passez pour obtenir l'adresse, puis passez à cette adresse. Seuls les entiers ont un sens dans ce scénario. Rappelez-vous que les ordinateurs n'étaient pas toujours aussi rapides qu'ils le sont maintenant. C a été conçu au début des années 70 sur la base du travail de la fin des années 60, lorsque les ordinateurs étaient beaucoup plus lents.

Certaines langues dans la même tradition syntaxique que Java et C, tels que JavaScript, faire le switch juste une autre façon d'écrire if...else/if...else et ne limite pas le type en cours de vérification à des types entiers, peut-être parce que, étant conçu les années 90, cela est devenu une option réaliste. Ou peut-être juste parce que le concepteur de JavaScript (Brendan Eich) l'a préféré de cette façon.


Ci-dessous, Baadshah demande:

Par curiosité: Alors maintenant comment ses cordes de soutien ??? Pouvez-vous s'il vous plaît donner une idée?

D'abord, un peu de recul et de regarder le int cas:

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

Ce produit bytecode comme ceci:

 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

Nous pouvons voir la table de consultation sur la int en action.

Alors, comment faites-vous cela avec des chaînes? Eh bien, une réponse serait de simplement transformer le switch en une structure if...else if...else. Mais ils ont fait quelque chose de plus intelligent que: Ils ont utilisé le hashcode pour optimiser, puis utilisés equals pour protéger contre les collisions:

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

devient:

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

Voir ce qu'ils ont fait là-bas? Il s'agit essentiellement de deux switches maintenant: Un pour obtenir un nombre unique pour chaque cas basé sur le code de hachage (mais double vérification avec equals), puis le second à expédier.

+3

Par curiosité: Alors maintenant, comment son soutien Strings ??? Pouvez-vous s'il vous plaît donner une idée? –

+1

@Baadshah: Une très bonne question! J'ai mis à jour pour y remédier. –

+0

Merci Crowder.Awsome explication pour un commentaire simple. –

1

L'instruction JDK6 a fonctionné sur les types de données char, octet, int primitive et enum. Dans JDK 7, ils ont réalisé que java.lang.String est également une constante et a été ajoutée à la liste des types de données supportés par une instruction switch.

Par exemple, le code suivant fonctionne correctement dans 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(); 
} 

}

Questions connexes