Pourquoi dans un commutateur Java sur un wrapper Integer, une casse «char» ne compile-t-elle pas, mais la compilation est OK lorsque le commutateur est sur Byte?

18

Ne compile pas:

void test(Integer x) {
      switch (x) {
          case 'a':
      }
}

Compile OK:

void test(Byte x) {
      switch(x) {
          case 'a':
      }
}
ali gh
la source
1
L'entier est de 4 octets tandis que le caractère est de 2 octets. Donc, dans le premier cas, quel que soit le caractère que vous écrivez, il est plus petit que l'entier. Dans le deuxième cas, cependant, le caractère que vous avez écrit peut être plus grand que l'octet maximum, ce qui empêche l'exécution de cette casse.
Jaroslaw Pawlak
Cette explication est incorrecte. En effet, dans le 2ème exemple, le code dans le 'a'cas sera exécuté dans le cas qui xest l'octet 97. (Essayez-le si vous ne me croyez pas.) Pour la vraie explication, voir ma réponse.
Stephen C

Réponses:

19

Les raisons sont assez compliquées, mais elles se trouvent toutes dans les détails (en petits caractères si vous le souhaitez) de la spécification du langage Java.

Tout d'abord, le JLS 14.11 dit ce qui suit au sujet des switchdéclarations:

"Chaque constante de cas associée à l'instruction switch doit être compatible avec le type d'expression de l'instruction switch ( §5.2 )."

Cela signifie que 'a'doit être attribuable à Integeret Byte respectivement.

Mais cela ne semble pas juste:

  • On pourrait penser que puisque 'a' devrait être attribuable à une affectation Integercar char-> intest légale. (Toute charvaleur rentrera dans un int.)

  • Vous penseriez que puisque 'a' ne devrait PAS être attribuable à une affectation Byteparce que char-> byten'est PAS légal. (La plupart des charvaleurs ne rentrent pas dans un octet.)

En fait, ni l'un ni l'autre n'est correct. Pour comprendre pourquoi, nous devons lire ce que JLS 5.2 fait réellement sur ce qui est autorisé dans les contextes d'affectation.

"Les contextes d'affectation permettent d'utiliser l' un des éléments suivants :

  • une conversion d'identité (§5.1.1)
  • une conversion primitive élargie (§5.1.2)
  • une conversion de référence élargie (§5.1.5)
  • une conversion de référence élargie suivie d'une conversion de déballage
  • une conversion de référence élargie suivie d'une conversion de déballage, puis suivie d'une conversion primitive d'élargissement
  • une conversion de boxe (§5.1.7)
  • une conversion de boxe suivie d'une conversion de référence élargie
  • une conversion de déballage (§5.1.8)
  • une conversion unboxing suivie d'une conversion primitive élargie. "

Pour passer de 'a'à Integer, il faudrait 1 élargir la charvaleur à an intpuis encadrer la intà an Integer. Mais si vous regardez les combinaisons de conversions autorisées, vous ne pouvez pas faire une conversion primitive élargie suivie d'une conversion de boxe.

Par conséquent , 'a'à Integern'est pas autorisé. Cela explique l'erreur de compilation dans le premier cas.

On pourrait penser que 'a'to Byteest interdit car cela impliquerait une conversion de rétrécissement primitive ... qui n'est pas du tout dans la liste. En fait, les littéraux sont un cas particulier. JLS 5.2 poursuit en disant ce qui suit.

"De plus, si l'expression est une expression constante ( §15.28 ) de type octet, court, char ou int:

  • Une conversion primitive rétrécissante peut être utilisée si la variable est de type byte, short ou char, et que la valeur de l'expression constante est représentable dans le type de la variable.

  • Un rétrécissement de conversion primitive suivie d'une conversion de boxe peuvent être utilisés si la variable est de type Byte, Short, ou Character, et la valeur de l'expression constante est représentable dans l'octet de type, court, ou char respectivement « .

La seconde s'applique 'a'à Byte, car:

  • un littéral de caractère est une expression constante, et
  • la valeur de 'a'est 97décimale, qui se situe dans la plage de byte( -128à +127).

Cela explique pourquoi il n'y a pas d'erreur de compilation dans le deuxième exemple.


1 - Nous ne pouvons pas boxer 'a'vers a Characterpuis élargir Charactervers Integercar il Characterne s'agit pas d'un sous-type Java de Integer. Vous ne pouvez utiliser une conversion de référence élargie que si le type source est un sous-type du type cible.

Stephen C
la source
Pouvons-nous utiliser intcomme type de commutateur? (depuis char -> intl'élargissement primitif qui est autorisé)
AjahnCharles