ปัญหาการบรรจุอัตโนมัติและการยกเลิกกล่องเป็นปัญหาทั่วไปใน Java วันนี้เราจะดูปัญหาบางอย่างเกี่ยวกับการบรรจุและยกเลิกการกล่อง บทความนี้พูดคุยเกี่ยวกับสิ่งพื้นฐานที่สุดเกี่ยวกับการบรรจุและยกเลิกการกล่องแล้วดูที่ปัญหาที่เกี่ยวข้องกับการบรรจุและการแกะกล่องที่มักพบในการทดสอบเป็นลายลักษณ์อักษรด้านล่าง
1. บรรจุคืออะไร? Unboxing คืออะไร?
ในบทความก่อนหน้า Java มีประเภท wrapper ที่สอดคล้องกันสำหรับแต่ละประเภทข้อมูลพื้นฐาน สำหรับสาเหตุที่ประเภท wrapper มีให้สำหรับแต่ละประเภทข้อมูลพื้นฐานมันจะไม่ถูกอธิบายที่นี่ เพื่อนที่สนใจสามารถปรึกษาข้อมูลที่เกี่ยวข้อง ก่อน Java SE5 หากคุณต้องการสร้างวัตถุจำนวนเต็มที่มีค่า 10 คุณต้องทำสิ่งนี้:
การคัดลอกรหัสมีดังนี้:
จำนวนเต็ม i = จำนวนเต็มใหม่ (10);
ตั้งแต่ Java SE5 คุณลักษณะการชกมวยอัตโนมัติจะมีให้ หากคุณต้องการสร้างวัตถุจำนวนเต็มที่มีค่า 10 คุณเพียงแค่ต้องทำสิ่งนี้:
การคัดลอกรหัสมีดังนี้:
จำนวนเต็ม i = 10;
ในกระบวนการนี้วัตถุจำนวนเต็มที่สอดคล้องกันจะถูกสร้างขึ้นโดยอัตโนมัติตามค่าตัวเลขซึ่งเป็นการบรรจุ
แล้ว Unboxing คืออะไร? ตามชื่อหมายถึงมันสอดคล้องกับการบรรจุซึ่งจะแปลงประเภท wrapper โดยอัตโนมัติเป็นประเภทข้อมูลพื้นฐาน:
การคัดลอกรหัสมีดังนี้:
จำนวนเต็ม i = 10; // การบรรจุ
int n = i; // unbox
เพื่อให้ง่ายการบรรจุหมายถึงการแปลงชนิดข้อมูลพื้นฐานเป็นประเภท wrapper โดยอัตโนมัติ Unboxing หมายถึงการแปลงประเภท wrapper โดยอัตโนมัติเป็นประเภทข้อมูลพื้นฐาน
ตารางต่อไปนี้คือประเภท wrapper ที่สอดคล้องกับประเภทข้อมูลพื้นฐาน:
2. การบรรจุและการยกเลิกการบ็อกซิ่งเป็นอย่างไร?
หลังจากทำความเข้าใจแนวคิดพื้นฐานของการบรรจุในส่วนก่อนหน้านี้ส่วนนี้จะเข้าใจว่าการบรรจุและการยกเลิกการบ็อกซิ่งถูกนำไปใช้อย่างไร
ลองใช้คลาส Interger เป็นตัวอย่างและดูชิ้นส่วนของรหัสด้านล่าง:
ชั้นเรียนสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม i = 10; int n = i;}}หลังจากถอดรหัสไฟล์คลาสคุณจะได้รับเนื้อหาต่อไปนี้:
จากเนื้อหา bytecode ที่ได้รับจากการถอดรหัสจะเห็นได้ว่าวิธีการของจำนวนเต็ม (int) ของจำนวนเต็มถูกเรียกโดยอัตโนมัติเมื่อบรรจุ เมื่อยกเลิกการกล่องวิธีการ intvalue ของจำนวนเต็มจะถูกเรียกโดยอัตโนมัติ
คนอื่น ๆ มีความคล้ายคลึงกันเช่นคู่หรือตัวละคร เพื่อนที่ไม่เชื่อมันสามารถลองด้วยตนเองได้ด้วยตนเอง
ดังนั้นกระบวนการใช้งานการบรรจุและการยกเลิกการบ็อกซ์สามารถสรุปได้ในประโยคเดียว:
กระบวนการชกมวยถูกนำมาใช้โดยการเรียกใช้วิธีการของ wrapper ในขณะที่กระบวนการ Unboxing ถูกนำมาใช้โดยการเรียกใช้วิธี XXXVALUE ของ wrapper (xxx แสดงถึงประเภทข้อมูลพื้นฐานที่สอดคล้องกัน)
3. คำถามที่เกี่ยวข้องระหว่างการสัมภาษณ์
แม้ว่าคนส่วนใหญ่มีความชัดเจนเกี่ยวกับแนวคิดของการบรรจุและการยกเลิกการกล่อง แต่พวกเขาอาจไม่สามารถตอบคำถามเกี่ยวกับการบรรจุและยกเลิกการกล่องระหว่างการสัมภาษณ์และการทดสอบเป็นลายลักษณ์อักษร ด้านล่างนี้เป็นคำถามสัมภาษณ์ทั่วไปที่เกี่ยวข้องกับการบรรจุ/ยกเลิกกล่อง
1. ผลลัพธ์ผลลัพธ์ของรหัสต่อไปนี้คืออะไร?
ชั้นเรียนสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม i1 = 100; จำนวนเต็ม i2 = 100; จำนวนเต็ม i3 = 200; จำนวนเต็ม i4 = 200; system.out.println (i1 == i2); system.out.println (i3 == i4); บางทีเพื่อนบางคนอาจบอกว่าพวกเขาจะส่งออกเท็จหรือเพื่อนบางคนจะบอกว่าพวกเขาจะส่งออกจริง แต่ในความเป็นจริงผลลัพธ์คือ:
จริง
เท็จ
ทำไมผลลัพธ์ดังกล่าวจึงเกิดขึ้น? ผลลัพธ์ผลลัพธ์แสดงให้เห็นว่า i1 และ i2 ชี้ไปที่วัตถุเดียวกันในขณะที่ i3 และ i4 ชี้ไปที่วัตถุต่าง ๆ ณ จุดนี้คุณจะต้องดูซอร์สโค้ดเพื่อทราบความจริง รหัสต่อไปนี้คือการใช้งานเฉพาะของวิธีการของจำนวนเต็มของวิธีการ:
ค่าคงที่ค่าคงที่สาธารณะของสาธารณะ (int i) {ถ้า (i> = -128 && i <= integercache.high) ส่งคืน integercache.cache [i + 128]; elsereturn จำนวนเต็มใหม่ (i);}; การใช้งานคลาส IntegerCache คือ:
คลาสคงที่คลาสคงที่ integercache {คงที่ int high; แคชจำนวนเต็มสุดท้ายคงที่ []; คงที่ {int สุดท้ายต่ำ = -128; // ค่าสูงอาจถูกกำหนดค่าโดย PropertyInt H = 127; ถ้า (integercachehighpropvalue! = null) {// ใช้เวลานาน long.decode (Integercachehighpropvalue) .intvalue (); i = math.max (i, 127); // ขนาดอาร์เรย์สูงสุดคือจำนวนเต็ม max_valueh = math.min (i, integer.max_value - -low); K <cache.length; จากรหัสทั้งสองชิ้นนี้เมื่อสร้างวัตถุจำนวนเต็มผ่านวิธีการของค่าของค่าหากค่าอยู่ระหว่าง [-128, 127] การอ้างอิงถึงวัตถุที่มีอยู่แล้วใน IntegerCache.Cache จะถูกส่งคืน; มิฉะนั้นจะสร้างวัตถุจำนวนเต็มใหม่
ในรหัสข้างต้นค่าของ I1 และ I2 คือ 100 ดังนั้นวัตถุที่มีอยู่จะถูกนำมาจากแคชโดยตรงดังนั้น I1 และ I2 จึงชี้ไปที่วัตถุเดียวกันในขณะที่ I3 และ I4 ชี้ไปที่วัตถุที่แตกต่างกันตามลำดับ
2. ผลลัพธ์ผลลัพธ์ของรหัสต่อไปนี้คืออะไร?
คลาสสาธารณะชั้นหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {double i1 = 100.0; double i2 = 100.0; double i3 = 200.0; double i4 = 200.0; system.out.println (i1 == i2); system.out.println (i3 == i4); บางทีเพื่อนบางคนอาจคิดว่าผลลัพธ์ผลลัพธ์ก็เหมือนกับคำถามข้างต้น แต่อันที่จริงแล้วมันไม่ใช่ เอาต์พุตจริงคือ:
เท็จ
เท็จ
ด้วยเหตุผลเฉพาะผู้อ่านสามารถตรวจสอบการใช้งานของค่าของชั้นสองชั้น
ที่นี่ฉันจะอธิบายได้ว่าทำไมวิธีการที่มีค่าของชั้นเรียนสองชั้นจึงใช้การใช้งานที่แตกต่างจากวิธีการที่มีค่าของคลาสจำนวนเต็ม มันง่ายมาก: จำนวนค่าจำนวนเต็มในช่วงที่กำหนดมี จำกัด แต่หมายเลขจุดลอยตัวไม่ได้
โปรดทราบว่าการใช้วิธีการที่มีค่าของจำนวนเต็ม, สั้น, ไบต์, อักขระและความยาวนั้นคล้ายคลึงกัน
การใช้วิธีการของค่าของสองเท่าและลอยตัวคล้ายกัน
3. ผลลัพธ์ผลลัพธ์ของรหัสต่อไปนี้คืออะไร:
ชั้นเรียนสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {บูลีน i1 = เท็จ; บูลีน i2 = เท็จ; บูลีน i3 = true; บูลีน i4 = true; system.out.println (i1 == i2); system.out.println (i3 == i4); ผลลัพธ์ผลลัพธ์คือ:
จริง
จริง
สำหรับสาเหตุที่เป็นผลลัพธ์คุณจะชัดเจนอย่างรวดเร็วหลังจากอ่านซอร์สโค้ดของคลาสบูลีน ต่อไปนี้คือการใช้งานเฉพาะของวิธีการของบูลีน:
ค่าบูลีนแบบคงที่สาธารณะ (บูลีน b) {return (b? true: false);} และอะไรคือความจริงและเท็จ? 2 คุณสมบัติสมาชิกคงที่ถูกกำหนดในบูลีน:
บูลีนสุดท้ายคงที่สาธารณะจริง = ใหม่บูลีน (จริง);/** * วัตถุ </code> boolean </code> ที่สอดคล้องกับค่าดั้งเดิม * <code> false </code> */Public Static Final Boolean False = ใหม่บูลีน (เท็จ);
ณ จุดนี้ทุกคนควรเข้าใจว่าทำไมผลลัพธ์ข้างต้นจึงเป็นจริง
4. พูดถึงความแตกต่างระหว่างจำนวนเต็ม i = ใหม่จำนวนเต็ม (xxx) และจำนวนเต็ม i = xxx;
แน่นอนหัวข้อนี้เป็นของประเภทที่ค่อนข้างกว้าง แต่ต้องตอบประเด็นสำคัญ ให้ฉันสรุปความแตกต่างสองประการต่อไปนี้:
1) วิธีแรกจะไม่กระตุ้นกระบวนการชกมวยอัตโนมัติ ในขณะที่วิธีที่สองจะทริกเกอร์;
2) ความแตกต่างในประสิทธิภาพการดำเนินการและการใช้ทรัพยากร วิธีการที่สองของประสิทธิภาพการดำเนินการและการใช้ทรัพยากรดีกว่าวิธีแรกโดยทั่วไป (โปรดทราบว่านี่ไม่ใช่สัมบูรณ์)
5. ผลลัพธ์ผลลัพธ์ของโปรแกรมต่อไปนี้คืออะไร?
คลาสสาธารณะหลัก {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม a = 1; จำนวนเต็ม b = 2; จำนวนเต็ม c = 3; จำนวนเต็ม d = 3; จำนวนเต็ม e = 321; จำนวนเต็ม f = 321; ยาว g = 3l; 2l; system.out.println (c == d); system.out.println (e == f); system.out.println (c == (a+b)); system.out.println (c.equals (a+b)); system.println (g == (a+b)); อย่าดูผลลัพธ์ผลลัพธ์ก่อนผู้อ่านจะคิดถึงผลลัพธ์ผลลัพธ์ของรหัสนี้ด้วยตนเอง สิ่งที่ควรสังเกตที่นี่คือเมื่อตัวดำเนินการทั้งสองของตัวดำเนินการ "==" มีการอ้างอิงถึงประเภท wrapper มันจะเปรียบเทียบว่าตัวชี้เป็นวัตถุเดียวกันและหากหนึ่งในตัวถูกดำเนินการเป็นนิพจน์ (นั่นคือมีการดำเนินการทางคณิตศาสตร์) มันจะเปรียบเทียบค่าตัวเลข ( นอกจากนี้สำหรับประเภท wrapper วิธีการเท่ากับไม่ได้ทำการแปลงประเภท หลังจากทำความเข้าใจกับ 2 คะแนนเหล่านี้ผลลัพธ์เอาต์พุตข้างต้นจะชัดเจนอย่างรวดเร็ว:
จริง
เท็จ
จริง
จริง
จริง
เท็จ
จริง
ไม่มีข้อสงสัยเกี่ยวกับผลลัพธ์ผลลัพธ์ที่หนึ่งและครั้งที่สอง ในประโยคที่สามเนื่องจาก A+B มีการดำเนินการทางคณิตศาสตร์มันจะกระตุ้นกระบวนการ Unboxing อัตโนมัติ (วิธีการ intvalue จะถูกเรียก) ดังนั้นพวกเขาจึงเปรียบเทียบว่าค่าเท่ากันหรือไม่ สำหรับ C.Equals (A+B) กระบวนการ Unboxing อัตโนมัติจะถูกเรียกใช้ก่อนจากนั้นกระบวนการบรรจุอัตโนมัติจะถูกเรียกใช้ กล่าวคือ A+B แต่ละคนจะเรียกวิธีการ intvalue และหลังจากได้รับค่าหลังจากการดำเนินการเพิ่มเติมจะมีการเรียกวิธีการเปรียบเทียบจำนวนเต็ม สิ่งนี้เป็นจริงสำหรับสิ่งต่อไปนี้ แต่ให้ความสนใจกับผลลัพธ์ที่สองถึงสุดท้ายและสุดท้าย (ถ้าค่าเป็นประเภท int กระบวนการชกมวยเรียกจำนวนเต็ม valueof; หากเป็นประเภทยาววิธีการชกมวยเรียกใช้ยาว
ข้างต้นเป็นความเข้าใจอย่างลึกซึ้งเกี่ยวกับการบรรจุและการแกะกล่องใน Java ที่แนะนำโดยบรรณาธิการ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!