คำอธิบายโดยละเอียดเกี่ยวกับการบรรจุ Java และ Unboxing
คำนำ:
เพื่อทำความเข้าใจแนวคิดของการบรรจุและการยกเลิกการกล่องคุณต้องเข้าใจประเภทข้อมูล Java
กล่อง: แพ็คเกจประเภทพื้นฐานที่มีประเภทอ้างอิงที่สอดคล้องกันเพื่อให้พวกเขามีคุณสมบัติของวัตถุ int บรรจุเป็นจำนวนเต็มลอยบรรจุไว้ในลอย
Unboxing: ตรงกันข้ามกับการชกมวยให้ลดความซับซ้อนของวัตถุประเภทอ้างอิงไปยังข้อมูลประเภทค่า
จำนวนเต็ม A = 100; นี่คือการชกมวยอัตโนมัติ (คอมไพเลอร์เรียกค่าจำนวนเต็มแบบคงที่ (int i)) int b = จำนวนเต็มใหม่ (100); นี่คือมวยอัตโนมัติ
ดูรหัสต่อไปนี้
M1
ประเภทข้อมูลระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง args []) {dataType dt = datatype ใหม่ (); dt.m11 (); dt.M12 (); } โมฆะสาธารณะ m11 () {จำนวนเต็ม A = จำนวนเต็มใหม่ (100); จำนวนเต็ม b = 100; System.out.println ("ผลลัพธ์ M11" + (a == b)); } โมฆะสาธารณะ M12 () {จำนวนเต็ม A = New Integer (128); จำนวนเต็ม b = 128; System.out.println ("m12 result" + (a == b)); -ผลการพิมพ์คืออะไร?
M11 ผลลัพธ์ที่ผิดพลาด M12 ผลลัพธ์เป็นเท็จ
"==" เปรียบเทียบที่อยู่ในขณะที่ที่อยู่ของวัตถุทั้งสอง A และ B นั้นแตกต่างกันนั่นคือพวกเขาเป็นสองวัตถุดังนั้นพวกเขาจึงเป็นเท็จ
การแยกวิเคราะห์ไบต์ผ่าน Javap เนื้อหามีดังนี้
โมฆะสาธารณะ M11 (); รหัส: 0: ใหม่ #44; // คลาส Java/Lang/Integer 3: Dup 4: Bipush 100 6: Invokespecial #46; // วิธีการ java/lang/integer. "<init>" :( i) v 9: store_1 10: bipush 100 12: invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 15: store_2 16: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 19: ใหม่ #59; // คลาส Java/Lang/StringBuilder 22: DUP 23: LDC #61; // สตริง M11 ผลลัพธ์ 25: Invokespecial #63; // วิธีการ java/lang/stringbuilder. "<init>" :( ljava/lang/string;) v 28: aload_1 29: aload_2 30: if_acmpne 37 33: iconst_1 34: goto 38 37: iconst_0 38: Invokevirtual #66; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 41: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/string; 44: invokevirtual #74; // วิธีการ java/io/printstream.println: (ljava/lang/string;) v 47: ส่งคืนโมฆะสาธารณะ M12 (); รหัส: 0: ใหม่ #74; // คลาส Java/Lang/Integer 3: Dup 4: Sipush 128 7: Invokespecial #46; // วิธีการ java/lang/integer. "<init>" :( i) v 10: store_1 11: sipush 128 14: invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 17: store_2 18: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 21: ใหม่ #59; // คลาส Java/Lang/StringBuilder 24: DUP 25: LDC #82; // สตริง M12 ผลลัพธ์ 27: Invokespecial #63; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 43: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/stringbuilder; 46: invokevirtual #74; // วิธีการ java/io/printstream.println: (ljava/lang/string;) v 49: return </init> </init> </init> </init>
M2
ประเภทข้อมูลระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง args []) {dataType dt = datatype ใหม่ (); dt.m21 (); dt.m22 (); } โมฆะสาธารณะ M21 () {จำนวนเต็ม A = New Integer (100); จำนวนเต็ม b = จำนวนเต็มใหม่ (100); System.out.println ("M21 result" + (a == b)); } โมฆะสาธารณะ M22 () {จำนวนเต็ม A = New Integer (128); จำนวนเต็ม b = จำนวนเต็มใหม่ (128); System.out.println ("M22 result" + (a == b)); -ผลการพิมพ์คือ
M21 ผลลัพธ์ Falsem22 ผลลัพธ์ที่เป็นเท็จ
A และ B ยังคงเป็นสองวัตถุ
Javap แยกเนื้อหา
โมฆะสาธารณะ M21 (); รหัส: 0: ใหม่ #44; // คลาส Java/Lang/Integer 3: Dup 4: Bipush 100 6: Invokespecial #46; // วิธีการ java/lang/integer. "<init>" :( i) v 9: store_1 10: ใหม่ #44; // คลาส Java/Lang/Integer 13: Dup 14: Bipush 100 16: Invokespecial #46; // วิธีการ java/lang/integer. "<init>" :( i) v 19: store_2 20: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 23: ใหม่ #59; // คลาส java/lang/stringbuilder 26: dup 27: ldc #84; // สตริง M21 ผลลัพธ์ 29: Invokespecial #63; // วิธีการ java/lang/stringbuilder. "<init>" :( ljava/lang/string;) v 32: aload_1 33: aload_2 34: if_acmpne 41 37: iconst_1 38: goto 42 41: iconst_0 42: invokevirtual #66; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 45: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/string; 48: invokevirtual #74; // วิธี java/io/printstream.println: (ljava/lang/string;) v 51: returnpublic โมฆะ M22 (); รหัส: 0: ใหม่ #74; // คลาส Java/Lang/Integer 3: Dup 4: Sipush 128 7: Invokespecial #46; // วิธีการ java/lang/integer. "<init>" :( i) v 10: store_1 11: ใหม่ #44; // คลาส Java/Lang/Integer 14: Dup 15: Sipush 128 18: Invokespecial #46; // วิธีการ java/lang/integer. "<init>" :( i) v 21: store_2 22: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 25: ใหม่ #59; // คลาส Java/Lang/StringBuilder 28: DUP 29: LDC 47: InvokeVirtual #70; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 47: invokevirtual #70; // วิธีการ java/lang/stringbuilder; 40: invokevirtual #70; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 47: invokevirtual #70; // วิธีการ java/lang/stringbuilder; java/lang/stringbuilder.toString :() ljava/lang/string; 50: Invokevirtual #74; // วิธีการ java/io/printstream.println: (ljava/lang/string;) v 53: return
M3
ประเภทข้อมูลระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง args []) {dataType dt = datatype ใหม่ (); dt.m31 (); dt.m32 (); } โมฆะสาธารณะ M31 () {จำนวนเต็ม A = 100; จำนวนเต็ม b = 100; System.out.println ("M31 result" + (a == b)); } โมฆะสาธารณะ M32 () {จำนวนเต็ม A = 128; จำนวนเต็ม b = 128; System.out.println ("M32 result" + (a == b)); -พิมพ์ผลลัพธ์
M31 ผลลัพธ์ Truem32 ผลลัพธ์เป็นเท็จ
เหตุใดจึงมีคนแรกที่เป็นจริงและเป็นเท็จที่สอง? สังเกตข้อมูลที่แยกวิเคราะห์โดย Javap
Javap แยกเนื้อหา
โมฆะสาธารณะ M31 (); รหัส: 0: Bipush 100 2: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 5: Store_1 6: Bipush 100 8: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 11: store_2 12: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 15: ใหม่ #59; // คลาส java/lang/stringbuilder 18: dup 19: ldc #88; // สตริง M31 ผลลัพธ์ 21: Invokespecial #63; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 37: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/string; 40: Invokevirtual #74; // วิธีการ java/io/printstream.println: (ljava/lang/string;) v 43: returnpublic เป็นโมฆะ M32 (); รหัส: 0: Sipush 128 3: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 6: ASTORE_1 7: SIPUSH 128 10: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 13: store_2 14: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 17: ใหม่ #59; // คลาส Java/Lang/StringBuilder 20: DUP 21: LDC #90; // สตริง M32 ผลลัพธ์ 23: Invokespecial #63; // วิธีการ java/lang/stringbuilder. "<init>" :( ljava/lang/string;) v 26: aload_1 27: aload_2 28: if_acmpne 35 31: iconst_1 32: goto 36 35: iconst_0 36: Invokevirt #66; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 39: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/string; 42: invokevirtual #74; // วิธีการ java/io/printstring.println: (ljava/lang/string;) v 45: return
M4
ประเภทข้อมูลระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง args []) {dataType dt = datatype ใหม่ (); dt.m41 (); dt.m42 (); } โมฆะสาธารณะ m41 () {จำนวนเต็ม a = integer.valueof (100); จำนวนเต็ม b = 100; System.out.println ("M41 result" + (a == b)); } โมฆะสาธารณะ m42 () {จำนวนเต็ม a = integer.valueof (128); จำนวนเต็ม b = 128; System.out.println ("M42 result" + (a == b)); -พิมพ์ผลลัพธ์
M41 ผลลัพธ์ Truem42 ผลลัพธ์ที่เป็นเท็จ
Javap แยกเนื้อหา
โมฆะสาธารณะ M41 (); รหัส: 0: Bipush 100 2: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 5: Store_1 6: Bipush 100 8: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 11: store_2 12: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 15: ใหม่ #59; // คลาส java/lang/stringbuilder 18: dup 19: ldc #92; // สตริง M41 ผลลัพธ์ที่ 21: Invokespecial #63; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 37: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/string; 40: Invokevirtual #74; // วิธีการ java/io/printstream.println: (ljava/lang/string;) v 43: returnpublic เป็นโมฆะ M42 (); รหัส: 0: Sipush 128 3: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 6: ASTORE_1 7: SIPUSH 128 10: Invokestatic #49; // วิธีการ java/lang/integer.valueof: (i) ljava/lang/integer; 13: store_2 14: getstatic #53; // ฟิลด์ java/lang/system.out: ljava/io/printstream; 17: ใหม่ #59; // คลาส Java/Lang/StringBuilder 20: DUP 21: LDC #94; // สตริง M42 ผลลัพธ์ 23: Invokespecial #63; // วิธีการ java/lang/stringbuilder. "<init>" :( ljava/lang/string;) v 26: aload_1 27: aload_2 28: if_acmpne 35 31: iconst_1 32: goto 36 35: iconst_0 36: Invokevirt #66; // วิธีการ java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 39: invokevirtual #70; // วิธีการ java/lang/stringbuilder.toString :() ljava/lang/string; 42: invokevirtual #74; // วิธีการ java/io/printstream.println: (ljava/lang/string;) v 45: return}
วิเคราะห์
Javap เป็นเครื่องมือที่มาพร้อมกับ Java มันสามารถถอดรหัสหรือดู bytecode ที่สร้างโดยคอมไพเลอร์ Java (รหัสด้านบนใช้เพียงข้อมูล JAVAP -C เท่านั้น) มันเป็นเครื่องมือที่ดีสำหรับการวิเคราะห์รหัส สำหรับรายละเอียดโปรด Google
มาดู M4 ก่อน ทำไม“ จริง” ถึงปรากฏในผลการทำงาน? จริงหมายความว่า A และ B เป็นวัตถุเดียวกัน
แต่วัตถุ A ถูกสร้างขึ้นโดยการเรียกจำนวนเต็ม ValueOf () และ B เป็นวัตถุที่สร้างขึ้นโดยการชกมวยอัตโนมัติ ทำไมมันถึงเป็นวัตถุเดียวกัน? มาดู Bytecode อีกครั้ง ท้ายที่สุดโปรแกรม Java พึ่งพาเครื่องเสมือนเพื่อเรียกใช้ bytecode
วิธี M41 จะใช้เฉพาะค่าของ () หนึ่งครั้ง แต่จะปรากฏขึ้นสองครั้งใน bytecode ซึ่งหมายความว่าค่าของ () เรียกอีกอย่างว่าระหว่างการชกมวยอัตโนมัติ
ต่อไปนี้คือการดำเนินการเฉพาะของมูลค่า ()
/** * ส่งคืนอินสแตนซ์ <tt> จำนวนเต็ม </tt> แทนค่า * <tt> int </tt> ที่ระบุ * หากไม่จำเป็นต้องใช้อินสแตนซ์ <tt> จำนวนเต็มใหม่ </tt> วิธีนี้ควรใช้วิธีนี้ * โดยทั่วไปควรใช้ในการตั้งค่ากับตัวสร้าง * {@link #integer (int)} เนื่องจากวิธีนี้น่าจะให้พื้นที่และประสิทธิภาพที่ดีขึ้นอย่างมีนัยสำคัญโดยการแคช * ค่าที่ร้องขอบ่อยครั้ง * * @param ฉันเป็นค่า <code> int </code> * @return a <tt> อินสแตนซ์ </tt> อินสแตนซ์แทน <tt> i </tt> * @Since 1.5 */ค่าคงที่ค่าคงที่สาธารณะ (int i) {final int offset = 128; ถ้า (i> = -128 && i <= 127) {// ต้องแคชส่งคืน IntegerCache.cache [i + ออฟเซ็ต];} ส่งคืนจำนวนเต็มใหม่ (i);};};ในตัวเลขระหว่าง [-128, 127], ค่าของการส่งคืนวัตถุในแคชดังนั้นการโทรทั้งสองจึงส่งคืนวัตถุเดียวกัน
ขอบคุณสำหรับการอ่านฉันหวังว่ามันจะช่วยคุณได้ ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!