Warum wird bei einem Java 8-Switch über einen Integer-Wrapper ein 'char'-Fall nicht kompiliert, aber die Kompilierung ist in Ordnung, wenn der Switch über Byte ist?



java-8 switch-statement (1)

Kompiliert nicht:

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

Kompiliert OK:

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

Die Gründe sind ziemlich kompliziert, aber sie liegen alle in den Details ( Kleingedrucktes, wenn Sie möchten) der Java-Sprachspezifikation.

Zunächst sagt der JLS 14.11 Folgendes über switch Anweisungen:

"Jede mit der switch-Anweisung §5.2 muss mit dem Typ des Ausdrucks der switch-Anweisung ( §5.2 ) §5.2 ."

Dies bedeutet, dass 'a' einer Integer bzw. einem Byte zuweisbar sein muss.

Das klingt aber nicht richtig:

  • Sie würden denken, dass 'a' einer Integer zuweisbar sein sollte , da die Zuweisung von char -> int zulässig ist. (Jeder char passt in ein int .)

  • Sie würden denken, dass 'a' NICHT einem Byte zuweisbar sein sollte , da die Zuweisung von char -> byte NICHT zulässig ist. (Die meisten char passen nicht in ein Byte.)

In der Tat ist keines von diesen richtig. Um zu verstehen, warum, müssen wir in §5.2 lesen, was in Zuweisungskontexten zulässig ist.

"Zuweisungskontexte ermöglichen die Verwendung einer der folgenden Möglichkeiten:

  • eine Identitätskonvertierung (§5.1.1)
  • eine sich erweiternde primitive Konvertierung (§5.1.2)
  • eine erweiterte Referenzkonvertierung (§5.1.5)
  • Eine erweiterte Referenzkonvertierung, gefolgt von einer Unboxing-Konvertierung
  • Eine erweiterte Referenzkonvertierung, gefolgt von einer Unboxing-Konvertierung, gefolgt von einer erweiterten primitiven Konvertierung
  • eine Boxing-Konvertierung (§5.1.7)
  • eine Boxing-Konvertierung, gefolgt von einer erweiterten Referenzkonvertierung
  • eine Unboxing-Konvertierung (§5.1.8)
  • eine Unboxing-Konvertierung, gefolgt von einer erweiterten primitiven Konvertierung. "

Um von 'a' zu Integer , müssten wir den char Wert 1 auf einen int Wert erweitern und dann den int Wert auf einen int Wert setzen. Wenn Sie sich jedoch die zulässigen Kombinationen von Konvertierungen ansehen, können Sie keine erweiterte primitive Konvertierung gefolgt von einer Boxing-Konvertierung ausführen.

Daher ist 'a' zu Integer nicht erlaubt. Dies erklärt den Kompilierungsfehler im ersten Fall.

Sie würden denken, dass 'a' zu Byte nicht Byte ist, da dies eine primitive Verengungskonvertierung beinhalten würde ... die überhaupt nicht in der Liste enthalten ist. Literale sind in der Tat ein Sonderfall. §5.2 führt Folgendes aus.

"Wenn der Ausdruck ein konstanter Ausdruck ( §15.28 ) vom Typ Byte, Short, Char oder Int ist:

  • Eine einschränkende primitive Konvertierung kann verwendet werden, wenn die Variable vom Typ Byte, Short oder Char ist und der Wert des konstanten Ausdrucks im Typ der Variablen darstellbar ist.

  • Eine einschränkende primitive Konvertierung, gefolgt von einer Boxing-Konvertierung, kann verwendet werden, wenn die Variable vom Typ Byte , Short oder Character ist und der Wert des konstanten Ausdrucks im Typ Byte, Short bzw. Char darstellbar ist.

Die zweite davon gilt für 'a' zu Byte , weil:

  • Ein Zeichenliteral ist ein konstanter Ausdruck
  • Der Wert von 'a' ist 97 Dezimal, was innerhalb des Bereichs für byte ( -128 bis +127 ) liegt.

Dies erklärt, warum im zweiten Beispiel kein Kompilierungsfehler vorliegt.

1 - Es ist nicht möglich 'a' in ein Character einzufügen und dann das Character auf Integer da Character kein Java-Untertyp von Integer . Sie können eine erweiterte Referenzkonvertierung nur verwenden, wenn der Quelltyp ein Subtyp des Zieltyps ist.





switch-statement