พฤติกรรมที่ประกอบไปด้วยสามแปลกของ Java เมื่อกำหนดค่า Java กำลังทำอะไรอยู่เบื้องหลังเพื่อให้สิ่งนี้เกิดขึ้น?


10

ไม่กี่วันที่ผ่านมาฉันพบกับสถานการณ์ที่น่าสนใจที่ฉันไม่สามารถหาเอกสารใด ๆ เกี่ยวกับว่า Java ให้เหตุผลต่อไปนี้ได้หรือไม่ (ตัวอย่างข้อมูลนี้เป็นเพียงรูปแบบของข้อบกพร่อง)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

ในตัวอย่างด้านบน:

ถ้า bool = true คุณจะได้ค่า '5'

แต่ถ้า bool = false คุณจะได้รับข้อยกเว้นตัวชี้ null เมื่อพยายามประเมินการดำเนินการแบบไตรภาค ไม่ใช่คำสั่งพิมพ์


ในการแก้ไขปัญหานี้ฉันแค่เปลี่ยน 'ผลลัพธ์' เป็น

Long result = bool ? Long.valueOf(intVal) : longVal;

การทำเช่นนี้จะให้พฤติกรรมตามที่ฉันต้องการ:

ถ้า bool = true คุณจะได้ค่า '5'

แต่ถ้า bool = false คุณจะได้ 'null'


ตอนนี้ส่วนที่สนุกคือถ้าคุณแยกสิ่งนี้เป็นคำสั่ง if / else ปกติแล้ว java จะไม่อนุญาตให้คุณคอมไพล์

longVal = intVal; 

แต่มันก็ไม่ได้จับผ่านทางผู้ประกอบการที่สาม ดังนั้น Java กำลังทำอะไรเพื่อให้เป็นศูนย์ในข้อมูลโค้ดต้นฉบับ

(java 11)

คำตอบ:


10

เมื่อคุณทำสิ่งนี้:

Long result = bool ? intVal : longVal

นิพจน์นี้ส่งคืน a longและเมื่อboolเป็นเท็จจะพยายาม unboxe nullเป็นค่า Long เพื่อให้พอดีกับresultตัวแปรและส่ง NPE

เมื่อคุณทำสิ่งนี้:

Long result = bool ? Long.valueOf(intVal) : longVal

นิพจน์นี้กลับมาLongแล้วไม่จำเป็นต้องยกเลิกการทำกล่องและกำหนดnullค่าให้กับresultตัวแปรเรียบร้อยแล้ว

อ้างอิง:

ตามที่กล่าวไว้ในส่วนความเห็นเพื่อทำความเข้าใจว่าทำไมสิ่งนี้ถึงเกิดขึ้นให้ตรวจสอบหัวข้อต่อไปนี้ของ JLS:


ฉันประหลาดใจคุณตารางอ้างอิงที่แตกต่างกัน15.25 A ถึง Eที่ "ชัดเจน" ที่จำนวนเต็ม / ยาวส่งผลให้เกิด bnp (จำนวนเต็มยาว)
แมตต์

คำตอบที่ดี. โดยทั่วไปเมื่อฉันไม่มีความคิดจริง ๆ สิ่งที่เกิดขึ้นภายในฉันขอแนะนำให้ดูในไบต์ที่รวบรวมซึ่งเผยให้เห็นเกือบตรงสิ่งที่อธิบาย อย่างน้อยเมื่อทำการแยกข้อมูลโค้ดขนาดเล็กนั่นเป็นเรื่องของการฝึกอบรมมากขึ้นวิธีการอ่านและทำความเข้าใจ
Jan Held

ในฐานะที่เป็นJLS ส่วน 5.6.2กล่าวว่า: "ถ้าตัวถูกดำเนินการใด ๆ เป็นประเภทอ้างอิงจะถูกแปลงเป็น unboxing แปลง"; จากนั้นจึงใช้ "การแปลงแบบเปิดกว้าง (§5.1.2) [.. ]"
Diego Magdaleno
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.