Mengapa dalam Java beralih lebih dari pembungkus Integer, apakah case 'char' tidak dikompilasi, tetapi kompilasi OK ketika switch lebih dari Byte?

18

Tidak mengkompilasi:

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

Kompilasi OK:

void test(Byte x) {
      switch(x) {
          case 'a':
      }
}
ali gh
sumber
1
Integer adalah 4 byte sedangkan char adalah 2 byte. Jadi dalam kasus pertama, tidak peduli karakter apa yang Anda tulis, itu lebih kecil dari integer. Namun dalam kasus kedua, karakter yang Anda tulis bisa lebih besar dari byte maksimum, membuat case tersebut tidak pernah dieksekusi.
Jaroslaw Pawlak
Penjelasan itu salah. Memang, pada contoh ke-2, kode dalam 'a'case akan dieksekusi dalam case yaitu xbyte 97. (Cobalah jika Anda tidak percaya kepada saya.) Untuk penjelasan sesungguhnya, lihat jawaban saya.
Stephen C

Jawaban:

19

Alasannya agak rumit, tetapi semuanya ada dalam rincian ( cetak halus jika Anda suka) dari Spesifikasi Bahasa Jawa.

Pertama, JLS 14.11 mengatakan yang berikut tentang switchpernyataan:

"Setiap konstanta kasus yang terkait dengan pernyataan sakelar harus sesuai dengan jenis Ekspresi pernyataan sakelar ( §5.2 )."

Ini berarti bahwa 'a'perlu ditugaskan Integerdan Byte masing - masing.

Tapi itu tidak terdengar benar:

  • Anda akan berpikir bahwa karena 'a' harus ditugaskan ke Integerkarena char-> inttugas adalah sah. ( charNilai apa pun akan cocok dengan int.)

  • Anda akan berpikir bahwa karena 'a' TIDAK boleh ditugaskan ke Bytekarena char-> byte tugas TIDAK sah. (Sebagian besar charnilai tidak akan masuk ke dalam byte.)

Faktanya, tidak ada yang benar. Untuk memahami mengapa, kita perlu membaca apa sebenarnya JLS 5.2 tentang apa yang diperbolehkan dalam konteks penugasan.

"Konteks penugasan memungkinkan penggunaan salah satu dari berikut ini :

  • konversi identitas (§5.1.1)
  • konversi pelebaran primitif (§5.1.2)
  • konversi referensi pelebaran (§5.1.5)
  • konversi referensi pelebaran diikuti oleh konversi unboxing
  • konversi referensi pelebaran diikuti oleh konversi unboxing, kemudian diikuti oleh konversi primitif pelebaran
  • konversi tinju (§5.1.7)
  • konversi tinju diikuti oleh konversi referensi pelebaran
  • konversi unboxing (§5.1.8)
  • konversi unboxing diikuti oleh konversi primitif pelebaran. "

Untuk beralih dari 'a'ke Integer, kita perlu 1 memperluas charnilai ke intkotak lalu intke Integer. Tetapi jika Anda melihat kombinasi konversi yang diizinkan, Anda tidak dapat melakukan konversi primitif pelebaran diikuti oleh konversi tinju.

Karenanya 'a'untuk Integertidak diperbolehkan. Ini menjelaskan kesalahan kompilasi dalam kasus pertama.

Anda akan berpikir bahwa 'a'untuk Bytetidak diizinkan karena itu akan melibatkan konversi penyempitan primitif ... yang tidak ada dalam daftar sama sekali. Padahal, literal adalah kasus khusus. JLS 5.2 selanjutnya mengatakan yang berikut.

"Selain itu, jika ekspresi adalah ekspresi konstan ( §15.28 ) dari tipe byte, pendek, char, atau int:

  • Konversi penyempitan primitif dapat digunakan jika variabelnya adalah tipe byte, pendek, atau char, dan nilai ekspresi konstan dapat diwakili dalam jenis variabel.

  • Konversi penyempitan primitif diikuti oleh konversi tinju dapat digunakan jika variabel bertipe Byte,, Shortatau Character, dan nilai ekspresi konstan diwakili dalam byte jenis, pendek, atau karakter masing-masing. "

Yang kedua ini berlaku 'a'untuk Byte, karena:

  • karakter literal adalah ekspresi yang konstan, dan
  • nilai 'a'adalah 97desimal, yang berada dalam jangkauan untuk byte( -128untuk +127).

Ini menjelaskan mengapa tidak ada kesalahan kompilasi dalam contoh kedua.


1 - Kita tidak bisa kotak 'a'untuk Characterkemudian melebar Characterke Integerkarena Charactertidak subtipe Jawa Integer. Anda hanya dapat menggunakan konversi referensi pelebaran jika jenis sumber adalah subtipe dari jenis target.

Stephen C
sumber
Bisakah kita menggunakan inttipe switch? (karena char -> intpelebaran primitif yang diizinkan)
AjahnCharles