Por que, em um comutador Java sobre um wrapper Inteiro, um caso 'char' não é compilado, mas a compilação é boa quando o comutador termina em Byte?

18

Não compila:

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

Compila OK:

void test(Byte x) {
      switch(x) {
          case 'a':
      }
}
ali gh
fonte
11
Inteiro é de 4 bytes, enquanto char é de 2 bytes. Portanto, no primeiro caso, independentemente do caractere que você escreve, é menor que o número inteiro. No segundo caso, no entanto, o caractere que você escreveu pode ser maior que o byte máximo, fazendo com que esse caso nunca seja executado.
Jaroslaw Pawlak
Essa explicação está incorreta. De fato, no segundo exemplo, o código no 'a'caso será executado no caso que xé o byte 97. (Tente se você não acredita em mim.) Para obter uma explicação real, veja minha resposta.
Stephen C

Respostas:

19

Os motivos são bastante complicados, mas estão todos nos detalhes ( letras pequenas, se você preferir ) da Especificação de Linguagem Java.

Primeiro, o JLS 14.11 diz o seguinte sobre switchdeclarações:

"Toda constante de caso associada à instrução switch deve ser atribuída compatível com o tipo de expressão da instrução switch ( §5.2 )."

Isso significa que 'a'precisa ser atribuível Integere Byte respectivamente.

Mas isso não parece certo:

  • Você pensaria que desde que 'a' deve ser atribuível a uma Integerporque char-> int atribuição é legal. (Qualquer charvalor caberá em um int.)

  • Você pensaria que uma vez 'a' que NÃO deve ser atribuível a uma Byteporque char-> a byte atribuição NÃO é legal. (A maioria dos charvalores não cabe em um byte.)

De fato, nenhuma delas está correta. Para entender o porquê, precisamos ler o JLS 5.2 sobre o que é permitido nos contextos de atribuição.

"Os contextos de atribuição permitem o uso de um dos seguintes :

  • uma conversão de identidade (§5.1.1)
  • uma conversão primitiva alargada (§5.1.2)
  • uma conversão de referência ampliada (§5.1.5)
  • uma conversão de referência ampliada seguida por uma conversão de unboxing
  • uma conversão de referência de ampliação seguida por uma conversão de unboxing e, em seguida, uma conversão primitiva de ampliação
  • uma conversão de boxe (§5.1.7)
  • uma conversão de boxe seguida por uma conversão de referência ampliada
  • uma conversão de unboxing (§5.1.8)
  • uma conversão de unboxing seguida por uma conversão primitiva de ampliação ".

Para passar de 'a'para Integer, precisaríamos 1 ampliar o charvalor para uma intcaixa e depois a intpara um Integer. Mas se você observar as combinações de conversões permitidas, não poderá fazer uma conversão primitiva de ampliação seguida por uma conversão de boxe.

Portanto 'a'a Integernão é permitido. Isso explica o erro de compilação no primeiro caso.

Você poderia pensar que 'a'a Bytenão é permitido porque isso envolveria uma conversão de restrição primitiva ... que não está na lista de todo. De fato, literais são um caso especial. O JLS 5.2 continua dizendo o seguinte.

"Além disso, se a expressão for uma expressão constante ( §15.28 ) do tipo byte, short, char ou int:

  • Uma conversão primitiva de restrição pode ser usada se a variável for do tipo byte, curta ou char, e o valor da expressão constante for representável no tipo da variável.

  • Uma conversão primitivo estreitando seguido por uma conversão boxe pode ser usado se a variável é do tipo Byte, Shortou Character, e o valor da expressão constante é representável no tipo byte, curto, ou carvão animal, respectivamente ".

O segundo deles se aplica 'a'a Byte, porque:

  • um literal de caractere é uma expressão constante e
  • o valor de 'a'é 97decimal, que está dentro do intervalo de byte( -128para +127).

Isso explica por que não há erro de compilação no segundo exemplo.


1 - Não pode caixa 'a'a um Charactere depois ampliar Characterpara Integerporque Characternão é um subtipo Java Integer. Você só pode usar uma conversão de referência ampliada se o tipo de origem for um subtipo do tipo de destino.

Stephen C
fonte
Podemos usar intcomo o tipo de switch? (uma vez que char -> inté alargamento primitivo que é permitido)
AjahnCharles