ฮีปและสแต็กเป็นแนวคิดที่สำคัญมากในโครงสร้างข้อมูล Java บทความนี้จะวิเคราะห์ความแตกต่างระหว่างทั้งสองอย่างละเอียด สำหรับการอ้างอิงของคุณ รายละเอียดมีดังนี้:
ฮีปของ Java คือพื้นที่ข้อมูลรันไทม์ที่คลาสอ็อบเจ็กต์จัดสรรพื้นที่ อ็อบเจ็กต์เหล่านี้ถูกสร้างขึ้นผ่านคำสั่ง เช่น new, newaray, anewarray และ multianewarray และไม่ต้องการโค้ดโปรแกรมที่จะเผยแพร่อย่างชัดเจน ฮีปถูกรวบรวมโดยการรวบรวมขยะ ข้อดีของฮีปคือสามารถจัดสรรขนาดหน่วยความจำแบบไดนามิก และไม่จำเป็นต้องบอกอายุการใช้งานให้กับคอมไพเลอร์ล่วงหน้า เนื่องจากฮีปจะจัดสรรหน่วยความจำแบบไดนามิกขณะรันไทม์ และตัวรวบรวมขยะของ Java จะรวบรวมสิ่งเหล่านี้ที่ไม่ได้ใช้อีกต่อไปโดยอัตโนมัติ ข้อมูล แต่ข้อเสียคือเนื่องจากจำเป็นต้องจัดสรรหน่วยความจำแบบไดนามิกในขณะรันไทม์ ความเร็วในการเข้าถึงจึงช้า
ข้อดีของสแต็กคือความเร็วในการเข้าถึงเร็วกว่าฮีป เป็นรองจากรีจิสเตอร์เท่านั้น และสามารถแชร์ข้อมูลสแต็กได้ แต่ข้อเสียคือต้องกำหนดขนาดและอายุการใช้งานของข้อมูลที่จัดเก็บไว้ในสแต็กและไม่มีความยืดหยุ่น สแต็กส่วนใหญ่จะจัดเก็บตัวแปรพื้นฐานบางประเภท (int, short, long, byte, float, double, boolean, char) และตัวจัดการอ็อบเจ็กต์
คุณสมบัติพิเศษที่สำคัญมากของสแต็กคือสามารถแชร์ข้อมูลที่จัดเก็บไว้ในสแต็กได้ สมมติว่าเรายังกำหนด:
int = 3;
int ข = 3;
คอมไพเลอร์จะประมวลผล int a = 3 ก่อน โดยสร้างการอ้างอิงไปยังตัวแปร a บนสแต็ก จากนั้นตรวจสอบว่ามีค่า 3 บนสแต็กหรือไม่ หากไม่พบ จะเก็บค่า 3 ไว้ในนั้น จากนั้นชี้ไปที่ 3. จากนั้นประมวลผล int b = 3 หลังจากสร้างตัวแปรอ้างอิงของ b แล้ว เนื่องจากมีค่า 3 บนสแต็กอยู่แล้ว b จะถูกชี้ไปที่ 3 โดยตรง ด้วยวิธีนี้ จึงเกิดสถานการณ์ที่ a และ b ชี้ไปที่ 3 พร้อมกัน
ในเวลานี้ หากตั้งค่า a=4 อีกครั้ง คอมไพเลอร์จะค้นหาอีกครั้งว่ามีค่า 4 ในสแต็กหรือไม่ หากไม่เป็นเช่นนั้น จะเก็บค่า 4 ไว้และชี้ไปที่ 4 ถ้ามีอยู่แล้ว จะชี้ a ไปยังที่อยู่นี้โดยตรง ดังนั้นการเปลี่ยนแปลงค่า a จะไม่ส่งผลต่อค่า b
ควรสังเกตว่าการแบ่งปันข้อมูลประเภทนี้แตกต่างจากการแบ่งปันการอ้างอิงวัตถุสองวัตถุที่ชี้ไปยังวัตถุเดียวในเวลาเดียวกัน เพราะในกรณีนี้การแก้ไข a จะไม่ส่งผลกระทบต่อ b คอมไพเลอร์จะเสร็จสมบูรณ์ซึ่ง มีประโยชน์ในการประหยัดพื้นที่ หากตัวแปรอ้างอิงออบเจ็กต์แก้ไขสถานะภายในของออบเจ็กต์ จะส่งผลต่อตัวแปรอ้างอิงออบเจ็กต์อื่น
String เป็นข้อมูลประเภท wrapper พิเศษ สามารถใช้ได้:
สตริง str = สตริงใหม่ ("abc");สตริง str = "abc";
มีสองวิธีในการสร้างมัน วิธีแรกคือการใช้ new() เพื่อสร้างวัตถุใหม่ซึ่งจะถูกเก็บไว้ในฮีป ออบเจ็กต์ใหม่จะถูกสร้างขึ้นทุกครั้งที่มีการเรียก
วิธีที่สองคือสร้างตัวแปรอ้างอิงอ็อบเจ็กต์ str ของคลาส String บนสแต็กก่อน จากนั้นตรวจสอบว่ามีการจัดเก็บ "abc" ไว้ในสแต็กหรือไม่ ถ้าไม่ ให้เก็บ "abc" ไว้ในสแต็กและทำให้ str ชี้ไปที่ "abc ". ถ้ามี "abc" อยู่แล้ว ให้ชี้ str ไปที่ "abc" โดยตรง
เมื่อเปรียบเทียบว่าค่าในคลาสเท่ากันหรือไม่ ให้ใช้เมธอดเท่ากับ() เมื่อทดสอบว่าการอ้างอิงของคลาส wrapper สองตัวชี้ไปที่วัตถุเดียวกันหรือไม่ ให้ใช้ == ตัวอย่างต่อไปนี้แสดงให้เห็นถึงทฤษฎีข้างต้น
สตริง str1 = "abc"; String str2 = "abc"; System.out.println(str1==str2);
จะเห็นได้ว่า str1 และ str2 ชี้ไปที่วัตถุเดียวกัน
สตริง str1 = สตริงใหม่ ("abc"); สตริง str2 = สตริงใหม่ ("abc"); System.out.println(str1==str2);
การใช้ new คือการสร้างวัตถุที่แตกต่างกัน สร้างทีละรายการ
ดังนั้น หากคุณใช้วิธีแรกเพื่อสร้างสตริง "abc" หลายรายการ จริงๆ แล้วจะมีวัตถุเดียวในหน่วยความจำเท่านั้น วิธีเขียนนี้มีประโยชน์ต่อการประหยัดพื้นที่หน่วยความจำ ในเวลาเดียวกัน ก็สามารถปรับปรุงความเร็วในการทำงานของ โปรแกรมได้ในระดับหนึ่ง เนื่องจาก JVM จะกำหนดโดยอัตโนมัติว่าจำเป็นต้องสร้างออบเจ็กต์ใหม่ตามสถานการณ์จริงของข้อมูลในสแต็กหรือไม่ สำหรับโค้ดของ String str = new String("abc"); ออบเจ็กต์ใหม่จะถูกสร้างขึ้นในฮีปเสมอไม่ว่าค่าสตริงจะเท่ากันหรือจำเป็นต้องสร้างออบเจ็กต์ใหม่หรือไม่ก็ตาม จึงเพิ่มภาระให้กับ โปรแกรม
ในทางกลับกัน โปรดทราบ: เมื่อเรากำหนดคลาสโดยใช้รูปแบบ เช่น String str = "abc"; เราจะถือว่าวัตถุ str ของคลาส String ถูกสร้างขึ้นเสมอ หมดกังวลกับดัก! วัตถุอาจไม่ถูกสร้างขึ้น! แต่อาจชี้ไปที่วัตถุที่สร้างขึ้นก่อนหน้านี้แทน มีเพียงเมธอด new() เท่านั้นที่เราสามารถมั่นใจได้ว่าออบเจ็กต์ใหม่จะถูกสร้างขึ้นทุกครั้ง
เนื่องจากลักษณะของคลาส String ที่ไม่เปลี่ยนรูป เมื่อตัวแปร String จำเป็นต้องเปลี่ยนค่าบ่อยครั้ง คุณควรพิจารณาใช้คลาส StringBuffer เพื่อปรับปรุงประสิทธิภาพของโปรแกรม
ฉันหวังว่าสิ่งที่บทความนี้อธิบายจะเป็นประโยชน์ต่อการเรียนรู้การเขียนโปรแกรม Java ของทุกคน