การอ้างอิงถึงวัตถุจำนวนเต็มใน Java
ไม่มีตัวชี้ใน Java แต่ก็มีแนวคิดเกี่ยวกับการอ้างอิง สิ่งที่เราต้องการพูดถึงที่นี่คือว่าจำนวนเต็มเป็นวัตถุเดียวกันหรือไม่
1. มาดูรหัสหนึ่งก่อน:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม A1 = 100; จำนวนเต็ม b1 = a1; // อีกอันหนึ่งสามารถเป็น b1 = 100 ฟิลด์ฟิลด์ = null; ลอง {field = a1.getClass (). getDeclaredField ("value"); } catch (nosuchfieldexception e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ e.printstacktrace (); } catch (SecurityException e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ E.PrintStackTrace (); } field.setAccessible (จริง); ลอง {field.set (A1, 5000); } catch (unledalargumentexception e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ e.printstacktrace (); } catch (unglemalAccessException e) {// todo catch block catch auto-generated e.printstacktrace (); } system.out.println ("b1 ="+b1); จำนวนเต็ม C1 = 100; System.out.println ("c1 ="+c1); - ผลลัพธ์:
B1 = 5000
C1 = 5000
จากข้างต้นก่อนอื่นฉันต้องการอธิบายบางสิ่งที่นี่
1) สำหรับจำนวนเต็มจำนวนเต็มระหว่าง -128-127 ได้รับการเริ่มต้นและวางไว้ในจำนวนเต็ม หากมีการบรรจุวัตถุจะถูกนำมาจากมัน
2) B1 = A1 เป็นการกำหนดตัวเลขหรือวัตถุเดียวกันหรือไม่? สามารถเห็นได้จากผลลัพธ์ที่ B1 และ A1 ชี้ไปที่วัตถุเดียวกันไม่ใช่ค่าตัวเลขเดียวกัน
3) C1 = 100 หมายความว่าสำหรับค่าระหว่าง -128-127 วัตถุทั้งหมดที่ได้จาก IntegerCache หลังจากวัตถุจำนวนเต็มที่สอดคล้องกับ 100 มีการเปลี่ยนแปลงการบรรจุที่ตามมาของ 100 จะเปลี่ยนไป เนื่องจากเมื่อได้รับวัตถุในแคชจะใช้ดัชนีอาร์เรย์โดยไม่ต้องใช้การเปรียบเทียบเชิงตัวเลข
อย่างไรก็ตามการปรับเปลี่ยนแคชนี้จะเป็นอันตรายมากขึ้นดังนั้นอย่าคิด ใครจะรู้ว่าแพ็คเกจ Jar หรือแพลตฟอร์มใดที่จะแพ็ค 100 หยวน แต่ผลลัพธ์ไม่ใช่ 100 หยวนและมันจะพังในเวลานั้น
2. ผ่านคำอธิบายข้างต้นคำตอบคืออะไรถ้ามันเปลี่ยนไปเป็นสิ่งนี้
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม A1 = 200; จำนวนเต็ม B1 = A1; ฟิลด์ฟิลด์ = null; ลอง {field = a1.getClass (). getDeclaredField ("value"); } catch (nosuchfieldexception e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ e.printstacktrace (); } catch (SecurityException e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ E.PrintStackTrace (); } field.setAccessible (จริง); ลอง {field.set (A1, 5000); } catch (unledalargumentexception e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ e.printstacktrace (); } catch (unglemalAccessException e) {// todo catch block catch auto-generated e.printstacktrace (); } system.out.println ("b1 ="+b1); จำนวนเต็ม C1 = 200; System.out.println ("c1 ="+c1); - 3. จากนั้นเปลี่ยนมัน
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม A1 = จำนวนเต็มใหม่ (100); จำนวนเต็ม B1 = A1; ฟิลด์ฟิลด์ = null; ลอง {field = a1.getClass (). getDeclaredField ("value"); } catch (nosuchfieldexception e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ e.printstacktrace (); } catch (SecurityException e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ E.PrintStackTrace (); } field.setAccessible (จริง); ลอง {field.set (A1, 5000); } catch (unledalargumentexception e) {// todo บล็อก catch block ที่สร้างขึ้นอัตโนมัติ e.printstacktrace (); } catch (unglemalAccessException e) {// todo catch block catch auto-generated e.printstacktrace (); } system.out.println ("b1 ="+b1); จำนวนเต็ม C1 = 100; System.out.println ("c1 ="+c1); - คำตอบคืออะไร? สำหรับการดำเนินการใหม่วัตถุไม่ได้ถูกบรรจุไว้ แต่ถูกสร้างขึ้นในกอง
ไม่ยากที่จะเข้าใจหากคุณเข้าใจการชกมวยการแคชและการอ้างอิง คุณสามารถลองด้วยตัวเอง
มารับความรู้พื้นฐานก่อน
การติดต่อประเภทพื้นฐานและคลาส wrapper byte byte สั้น int inte จำนวนเต็มยาวลอยยาวลอยตัวอักขระสองตัวอักขระบูลีนบูลีนบูลีน
การติดต่อระหว่างชนิดข้อมูลพื้นฐานในแปดข้างต้นเป็นเฉพาะอักขระ int-> จำนวนเต็ม char-> การเปลี่ยนแปลงทั้งสองมีความสำคัญและส่วนที่เหลือเพียงแค่แปลงตัวอักษรตัวแรกเป็นตัวพิมพ์เล็ก
มาเรียนรู้เกี่ยวกับคุณสมบัติใหม่ของ JDK5: การบรรจุอัตโนมัติและการยกเลิกกล่อง
การชกมวยอัตโนมัติ: แปลงประเภทพื้นฐานเป็นประเภทคลาสบรรจุภัณฑ์
การยกเลิกกล่องอัตโนมัติ: แปลงประเภทคลาส wrapper เป็นประเภทพื้นฐาน
ระดับสาธารณะ demo_integer {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// ก่อน jdk1.5 int a = 100; จำนวนเต็ม A1 = จำนวนเต็มใหม่ (a); // ห่อประเภทข้อมูลพื้นฐานลงในวัตถุกล่อง int b = a1.intvalue (); // แปลงวัตถุเป็นชนิดข้อมูลพื้นฐานและ unbox // หลังจาก jdk1.5 int x = 100; จำนวนเต็ม x1 = x; // กล่องโดยอัตโนมัติแปลงประเภทข้อมูลพื้นฐานเป็นวัตถุ int y = x1 + x; // unbox โดยอัตโนมัติแปลงวัตถุเป็นประเภทข้อมูลพื้นฐาน}}สิ่งที่ควรทราบ
ระดับสาธารณะ demo_integer {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม a = null; int b = a + 100; // ชั้นล่างของการยกเลิกการบ็อกซ์อัตโนมัติจะเรียก a.intvalue (), a เป็นโมฆะและจะโยน nullpointerexception system.out.println (b); -คำถามสัมภาษณ์
ระดับสาธารณะ demo_integer {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม i1 = จำนวนเต็มใหม่ (97); จำนวนเต็ม i2 = จำนวนเต็มใหม่ (97); System.out.println (i1 == i2); System.out.println (i1.equals (i2)); System.out.println ("-------------"); จำนวนเต็ม i3 = จำนวนเต็มใหม่ (197); จำนวนเต็ม i4 = ใหม่จำนวนเต็ม (197); System.out.println (i3 == i4); System.out.println (i3.equals (i4)); System.out.println ("----------------"); -เอาท์พุท: เท็จจริง ------------------------------------------------------------------
เหตุผล:
ใหม่คือการเปิดพื้นที่ในหน่วยความจำฮีปและค่าที่อยู่การเปรียบเทียบตามธรรมชาติ (==) เป็นเท็จ
เนื่องจากจำนวนเต็มเขียนวิธีการเท่ากับเอาต์พุตเท่ากับเป็นจริง
คุณอาจรู้สึกว่ามันง่ายเกินไปและไม่มีเนื้อหาทางเทคนิคเพราะข้างต้นไม่ใช่ประเด็นให้ดูที่รหัสด้านล่าง
ระดับสาธารณะ demo_integer {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม i1 = 127; จำนวนเต็ม i2 = 127; System.out.println (i1 == i2); System.out.println (i1.equals (i2)); System.out.println ("--------------"); จำนวนเต็ม i3 = 128; จำนวนเต็ม i4 = 128; System.out.println (i3 == i4); System.out.println (i3.equals (i4)); System.out.println ("---------------"); -เอาท์พุท: จริงจริง --------------------------------------------------------------------------------------------------------------------------
เหตุผล:
ทำไมวัตถุสองชิ้นเมื่อ int มากกว่า 127? หมายเลข 127 รู้สึกคุ้นเคยมากหรือไม่?
-128 ถึง 127 เป็นช่วงค่าของไบต์ หากอยู่ในช่วงค่านี้การชกมวยอัตโนมัติจะไม่สร้างวัตถุใหม่และรับจากพูลคงที่
หากช่วงค่าของไบต์เกินวัตถุใหม่จะถูกสร้างขึ้น
แพ็คเลเยอร์พื้นฐานโดยอัตโนมัติและเรียกใช้วิธีการ () การวิเคราะห์ซอร์สโค้ดอย่างง่าย (JDK1.8):
จำนวนเต็มระดับสุดท้ายสาธารณะขยายจำนวนใช้งานได้เทียบเท่า <teger> {ค่าคงที่ของจำนวนเต็มสาธารณะ (int i) {// เมื่อฉัน> = -128 และ i <= 127 วัตถุในบัฟเฟอร์จะถูกดึงโดยตรงถ้า (i> = integercache.low && i <= integercache.high) ส่งคืนจำนวนเต็มใหม่ (i); // หากช่วงค่าไบต์เกินช่วงจะถูกสร้างขึ้นในหน่วยความจำฮีป} // คลาสด้านในทำหน้าที่เป็นบัฟเฟอร์คลาสส่วนตัวคงที่ integercache {คงสุดท้าย int low = -128; int สุดท้ายคงที่สูง; แคชจำนวนเต็มสุดท้ายคงที่ []; {// ค่าสูงอาจถูกกำหนดค่าโดยคุณสมบัติ int h = 127; String IntegercachehighPropValue = sun.misc.vm.gm.getSavedProperty ("java.lang.integer.integercache.high"); if (IntegerCachehighPropValue! = null) {ลอง {int i = parseInt (IntegerCachehighPropValue); i = math.max (i, 127); // ขนาดอาร์เรย์สูงสุดคือจำนวนเต็ม max_value h = math.min (i, integer.max_value -(-low) -1); } catch (numberFormatexception nfe) {// ถ้าคุณสมบัติไม่สามารถแยกวิเคราะห์เป็น int ได้ให้ละเว้น }} สูง = h; แคช = จำนวนเต็มใหม่ [(สูง - ต่ำ) + 1]; int j = ต่ำ; สำหรับ (int k = 0; k <cache.length; k ++) แคช [k] = จำนวนเต็มใหม่ (j ++); // ช่วง [-128, 127] ต้องถูกทำให้เป็นภายใน (jls7 5.1.7) ยืนยัน Integercache.high> = 127; } Private IntegerCache () {}}} 8 ประเภทพื้นฐานของคลาสการห่อและพูลวัตถุ
คลาส wrapper ประเภทพื้นฐานส่วนใหญ่ใน Java ใช้เทคโนโลยีการรวมการรวมกันอย่างต่อเนื่อง คลาสเหล่านี้เป็นไบต์สั้นจำนวนเต็มยาวตัวละครบูลีนและคลาสเสื้อคลุมอีกสองประเภทที่มีหมายเลขจุดลอยตัวจะไม่ถูกนำมาใช้ นอกจากนี้คลาส wrapper จำนวนเต็มห้าคลาสของไบต์สั้นจำนวนเต็มยาวอักขระสามารถใช้พูลวัตถุได้เฉพาะเมื่อค่าที่สอดคล้องกันน้อยกว่าหรือเท่ากับ 127 นั่นคือวัตถุไม่รับผิดชอบในการสร้างและจัดการวัตถุของคลาสเหล่านี้มากกว่า 127
ความรู้ขยาย
ในข้อกำหนด JVM แต่ละประเภทมีสระว่ายน้ำคงที่ของตัวเอง สระว่ายน้ำคงที่เป็นคอลเลกชันที่สั่งซื้อของค่าคงที่ที่ใช้โดยประเภทหนึ่งรวมถึงค่าคงที่โดยตรง (ประเภทดั้งเดิม, สตริง) และการอ้างอิงเชิงสัญลักษณ์สำหรับประเภทอื่น ๆ ฟิลด์และวิธีการ เหตุผลที่มันเป็นการอ้างอิงเชิงสัญลักษณ์มากกว่าการระบุประเภทอื่น ๆ โดยตรงในเวลาที่รวบรวมเป็นเพราะ Java ถูกผูกไว้แบบไดนามิกและเฉพาะในการรันไทม์เท่านั้นอินสแตนซ์การพึ่งพาประเภทเฉพาะจะถูกกำหนดตามกฎบางอย่าง นี่คือพื้นฐานสำหรับ Java ในการใช้ polymorphism
ใน JVM วงจรชีวิตทั้งหมดของคลาสเริ่มต้นจากการถูกโหลดลงในหน่วยความจำเครื่องเสมือนและจนกว่าจะถูกขนถ่ายออกจากหน่วยความจำ วงจรชีวิตทั้งหมดรวมถึง: การโหลดการตรวจสอบการเตรียมการแยกวิเคราะห์การเริ่มต้นการใช้งานและการขนถ่าย ขั้นตอนการแยกวิเคราะห์เป็นกระบวนการของเครื่องเสมือนการแทนที่สัญลักษณ์การอ้างอิงในพูลคงที่ด้วยการอ้างอิงโดยตรง
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com