Perché in uno switch Java su un wrapper Integer, un caso "char" non viene compilato, ma la compilazione è OK quando lo switch è su Byte?


18

Non compilare:

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

Compila OK:

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

1
Il numero intero è di 4 byte mentre il carattere char è di 2 byte. Quindi nel primo caso, indipendentemente dal carattere che scrivi, è più piccolo dell'intero. Nel secondo caso, tuttavia, il carattere che hai scritto potrebbe essere più grande del byte massimo, rendendo quel caso mai eseguito.
— Jaroslaw Pawlak,

Questa spiegazione non è corretta. In effetti, nel secondo esempio, il codice nel 'a'caso verrà eseguito nel caso in cui xsia il byte 97. (Provalo se non mi credi.) Per la vera spiegazione, vedi la mia risposta.
— Stephen C,

Risposte:


19

Le ragioni sono piuttosto complicate, ma sono tutte nei dettagli ( stampa fine se preferisci) della specifica del linguaggio Java.

Innanzitutto, JLS 14.11 afferma quanto segue sulle switchdichiarazioni:

"Ogni costante di caso associata all'istruzione switch deve essere compatibile con il tipo di espressione dell'istruzione switch ( §5.2 )."

Ciò significa che 'a'deve essere assegnabile a Integere Byte rispettivamente.

Ma questo non suona bene:

  • Penseresti che poiché 'a' dovrebbe essere assegnabile a un incarico Integerperché char-> intè legale. (Qualsiasi charvalore si adatta a un int.)

  • Penseresti che poiché 'a' NON dovrebbe essere assegnabile a Byteperché char-> l' byte assegnazione NON è legale. (La maggior parte dei charvalori non si adatta a un byte.)

In effetti, nessuno di questi è corretto. Per capire perché, dobbiamo leggere cosa JLS 5.2 in realtà su ciò che è consentito nei contesti di assegnazione.

"I contesti di assegnazione consentono l'uso di uno dei seguenti :

  • una conversione di identità (§5.1.1)
  • una conversione primitiva allargante (§5.1.2)
  • una conversione di riferimento allargata (§5.1.5)
  • una conversione di riferimento allargata seguita da una conversione unboxing
  • una conversione di riferimento allargata seguita da una conversione unboxing, quindi seguita da una conversione primitiva allargante
  • una conversione di boxe (§5.1.7)
  • una conversione di inscatolamento seguita da una conversione di riferimento allargata
  • una conversione unboxing (§5.1.8)
  • una conversione unboxing seguita da una conversione primitiva allargata. "

Per passare da 'a'a Integer, avremmo bisogno di 1 allargare il charvalore a un intquindi box inta a un Integer. Ma se osservi le combinazioni di conversioni consentite, non puoi fare una conversione primitiva allargata seguita da una conversione di boxe.

Quindi 'a'per Integernon è permesso. Questo spiega l'errore di compilazione nel primo caso.

Si potrebbe pensare che 'a'a Bytenon sia consentito perché ciò implicherebbe una conversione restrittiva primitiva ... che non è affatto nell'elenco. In effetti, i letterali sono un caso speciale. JLS 5.2 continua dicendo quanto segue.

"Inoltre, se l'espressione è un'espressione costante ( §15.28 ) di tipo byte, short, char o int:

  • Una conversione primitiva restrittiva può essere utilizzata se la variabile è di tipo byte, short o char e il valore dell'espressione costante è rappresentabile nel tipo di variabile.

  • Una conversione primitiva restrittiva seguita da una conversione di inscatolamento può essere utilizzata se la variabile è di tipo Byte, Shortoppure Character, e il valore dell'espressione costante è rappresentabile nel byte di tipo, breve o char rispettivamente ".

Il secondo si applica 'a'a Byte, perché:

  • un personaggio letterale è un'espressione costante, e
  • il valore di 'a'è 97decimale, che è compreso nell'intervallo per byte( -128a +127).

Questo spiega perché non c'è errore di compilazione nel secondo esempio.


1 - Non possiamo boxare 'a'a Charactere poi allargare Charactera Integerperché Characternon è un sottotipo Java di Integer. È possibile utilizzare una conversione di riferimento allargata solo se il tipo di origine è un sottotipo del tipo di destinazione.


Possiamo usare intcome tipo di interruttore? (dal momento char -> intche è consentito l'allargamento primitivo)
— AjahnCharles
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.