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.