เหตุใดในการสลับ Java บนตัวห่อหุ้มจำนวนเต็มตัวพิมพ์เล็ก 'char' ไม่ได้คอมไพล์ แต่การคอมไพล์ก็โอเคเมื่อสวิตช์อยู่เหนือไบต์?


18

ไม่ได้รวบรวม:

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

คอมไพล์ตกลง:

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

1
จำนวนเต็มคือ 4 ไบต์ในขณะที่ถ่านเท่ากับ 2 ไบต์ ดังนั้นในกรณีแรกไม่ว่าคุณจะเขียนตัวอักษรแบบใดมันมีขนาดเล็กกว่าจำนวนเต็ม อย่างไรก็ตามในกรณีที่สองตัวละครที่คุณเขียนอาจมีขนาดใหญ่กว่าไบต์สูงสุดทำให้กรณีนั้นไม่เคยดำเนินการ
Jaroslaw Pawlak

คำอธิบายนั้นไม่ถูกต้อง อันที่จริงในตัวอย่างที่ 2 รหัสใน'a'กรณีที่จะได้รับการดำเนินการในกรณีที่เป็นไบต์x 97(ลองถ้าคุณไม่เชื่อฉัน) สำหรับคำอธิบายที่แท้จริงให้ดูคำตอบของฉัน
Stephen C

คำตอบ:


19

เหตุผลค่อนข้างซับซ้อน แต่ทั้งหมดอยู่ในรายละเอียด ( พิมพ์ได้ดีหากคุณต้องการ) ของ Java Language Specification

ก่อนอื่นJLS 14.11พูดเกี่ยวกับswitchข้อความต่อไปนี้:

"ค่าคงที่ของทุกกรณีที่เกี่ยวข้องกับคำสั่ง switch จะต้องได้รับการกำหนดให้เข้ากันได้กับชนิดของ Expression ของคำสั่ง switch ( §5.2 )"

ซึ่งหมายความว่า'a'จะต้องกำหนดให้IntegerและByte ตามลำดับ

แต่นั่นไม่ถูกต้อง:

  • คุณคิดว่า'a' ควรจะมอบหมายให้Integerเพราะchar-> การint มอบหมายนั้นถูกกฎหมาย ( charค่าใด ๆจะพอดีกับ an int.)

  • คุณจะคิดว่าเนื่องจาก'a' ไม่ควรมอบหมายให้Byteเพราะchar-> การbyte มอบหมายนั้นไม่ถูกกฎหมาย ( charค่าส่วนใหญ่จะไม่พอดีกับไบต์)

ที่จริงแล้วสิ่งเหล่านี้ไม่ถูกต้อง เพื่อทำความเข้าใจว่าทำไมเราต้องอ่านสิ่งที่JLS 5.2จริงเกี่ยวกับสิ่งที่ได้รับอนุญาตในบริบทการมอบหมาย

"บริบทการมอบหมายให้ใช้อย่างใดอย่างหนึ่งต่อไปนี้ :

  • การแปลงข้อมูลประจำตัว (§5.1.1)
  • การแปลงดั้งเดิมแบบขยับขยาย (§5.1.2)
  • การแปลงการอ้างอิงที่กว้างขึ้น (§5.1.5)
  • การแปลงการอ้างอิงแบบขยายตามด้วยการแปลงแบบไม่ทำกล่อง
  • การแปลงการอ้างอิงแบบขยายตามด้วยการแปลงแบบไม่มีกล่องจากนั้นตามด้วยการแปลงแบบดั้งเดิมแบบขยับขยาย
  • การแปลงมวย (§5.1.7)
  • การแปลงมวยตามด้วยการแปลงการอ้างอิงที่กว้างขึ้น
  • การแปลง unboxing (§5.1.8)
  • การแปลงที่ไม่ทำกล่องแล้วตามด้วยการแปลงดั้งเดิมที่เปิดกว้าง "

ที่จะไปจาก'a'การIntegerที่เราจะต้อง1ขยายcharค่าไปยังintแล้วกล่องไปยังint Integerแต่ถ้าคุณดูชุดค่าผสมของการแปลงที่ได้รับอนุญาตคุณจะไม่สามารถทำการแปลงแบบดั้งเดิมได้ตามด้วยการแปลงแบบมวย

ดังนั้น'a'จะIntegerไม่ได้รับอนุญาต สิ่งนี้อธิบายถึงข้อผิดพลาดในการคอมไพล์ในกรณีแรก

คุณจะคิดว่า'a'จะByteไม่ได้รับอนุญาตเพราะนั่นจะเกี่ยวข้องกับการแปลงให้แคบลงดั้งเดิม ... ซึ่งไม่ได้อยู่ในรายการเลย แท้จริงแล้วตัวอักษรเป็นกรณีพิเศษ JLS 5.2พูดต่อไปนี้

"นอกจากนี้หากนิพจน์เป็นนิพจน์คงที่ ( §15.28 ) ของชนิดไบต์, ระยะสั้น, ถ่านหรือ int:

  • การแปลงดั้งเดิมแบบ จำกัด ให้แคบลงอาจใช้ถ้าตัวแปรเป็นประเภทไบต์สั้นหรือถ่านและค่าของนิพจน์คงที่นั้นสามารถแทนได้ในประเภทของตัวแปร

  • การกวดขันการแปลงดั้งเดิมตามด้วยการแปลงมวยอาจจะใช้ในกรณีที่ตัวแปรเป็นชนิดByte, ShortหรือCharacterและความคุ้มค่าของการแสดงออกคงเป็นแทนได้ในประเภทไบต์สั้นหรือถ่านตามลำดับ."

ที่สองเหล่านี้นำไปใช้กับ'a'การByteเพราะ:

  • ตัวอักษรตัวอักษรคือการแสดงออกอย่างต่อเนื่องและ
  • ค่าของ'a'เป็น97ทศนิยมซึ่งอยู่ในช่วงสำหรับbyte( -128ถึง+127)

สิ่งนี้อธิบายว่าทำไมไม่มีข้อผิดพลาดในการรวบรวมในตัวอย่างที่สอง


1 - เราไม่สามารถกล่อง'a'ไปCharacterแล้วขยายCharacterไปIntegerเพราะไม่ได้เป็นชนิดย่อยของCharacter Java Integerคุณสามารถใช้การแปลงการอ้างอิงที่กว้างขึ้นได้หากประเภทแหล่งที่มาเป็นประเภทย่อยของประเภทเป้าหมาย


เราสามารถใช้intเป็นสวิตช์ชนิดได้หรือไม่ (เนื่องจากchar -> intเป็นการขยายแบบดั้งเดิมซึ่งอนุญาต)
AjahnCharles
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.