1. คุณสมบัติ: getters และ setters
เมื่อโปรเจกต์ขนาดใหญ่ถูกพัฒนาโดยโปรแกรมเมอร์หลายสิบคนพร้อมๆ กัน ปัญหามักจะเกิดขึ้นหากพวกเขาจัดการกับข้อมูลที่จัดเก็บไว้ในฟิลด์คลาสแตกต่างกัน
บางทีผู้คนอาจไม่ได้ศึกษาเอกสารประกอบของชั้นเรียนโดยละเอียด หรือบางทีอาจไม่ได้อธิบายถึงทุกกรณี เป็นผลให้มีสถานการณ์บ่อยครั้งที่ข้อมูลภายในของออบเจ็กต์อาจ "เสียหาย" ทำให้ออบเจ็กต์ไม่ถูกต้อง
เพื่อหลีกเลี่ยงสถานการณ์เหล่านี้เป็นเรื่องปกติที่จะต้องทำให้ฟิลด์คลาสทั้งหมดเป็นส่วนตัวใน Java เฉพาะเมธอดของคลาสเท่านั้นที่สามารถแก้ไขตัวแปรของคลาสได้ ไม่มีเมธอดจากคลาสอื่นที่สามารถเข้าถึงตัวแปรได้โดยตรง
หากคุณต้องการให้คลาสอื่นสามารถรับหรือเปลี่ยนแปลงข้อมูลภายในออบเจกต์ของคลาสของคุณได้ คุณต้องเพิ่มเมธอดสองเมธในคลาสของคุณ — เมธอด get และเมธอด set ตัวอย่าง:
รหัส | บันทึก |
---|---|
|
private ฟิลด์ชื่อการเริ่มต้นของฟิลด์ผ่านตัวสร้าง getName() — วิธีนี้จะส่งกลับค่าของฟิลด์ชื่อsetName() — วิธีนี้จะเปลี่ยนค่าของฟิลด์ชื่อ |
ไม่มีคลาสอื่นใดที่สามารถเปลี่ยนค่าของฟิลด์ชื่อได้โดยตรง หากมีคนต้องการรับค่าของฟิลด์ชื่อ พวกเขาจะต้องเรียกใช้เมธอดgetName()
บนPerson
วัตถุ ถ้าบางโค้ดต้องการเปลี่ยนค่าของฟิลด์ชื่อ จะต้องเรียกเมธอดsetName()
บนPerson
วัตถุ
เมธอด นี้getName()
เรียกอีกอย่างว่า " getterสำหรับฟิลด์ชื่อ" และsetName()
เมธอดนี้เรียกว่า " setterสำหรับฟิลด์ชื่อ"
นี่เป็นวิธีการทั่วไป ใน 80-90% ของโค้ด Java ทั้งหมด คุณจะไม่เห็นตัวแปรสาธารณะในคลาส แต่จะถูกประกาศprivate
(หรือprotected
) แทน และแต่ละตัวแปรจะมีตัวรับและตัวตั้งสาธารณะ
วิธีการนี้ทำให้โค้ดยาวขึ้นแต่มีความน่าเชื่อถือมากขึ้น
การเข้าถึงคลาสตัวแปรโดยตรงก็เหมือนกับการเปลี่ยนรถของคุณผ่านเส้นสีเหลืองสองเส้นมันง่ายกว่าและเร็วกว่า แต่ถ้าทุกคนทำอย่างนั้น ทุกอย่างก็จะแย่ลงสำหรับทุกคน
สมมติว่าคุณต้องการสร้างคลาสที่อธิบายจุด ( x
, y
) นี่คือวิธีที่โปรแกรมเมอร์มือใหม่จะทำ:
class Point
{
public int x;
public int y;
}
นี่คือวิธีที่โปรแกรมเมอร์ Java ที่มีประสบการณ์จะทำ:
รหัส |
---|
|
รหัสยาวขึ้นหรือไม่ อย่างไม่ต้องสงสัย
แต่คุณสามารถเพิ่มการตรวจสอบพารามิเตอร์ให้กับ getters และ setters ตัวอย่างเช่น คุณสามารถตรวจสอบให้แน่ใจว่าx
และy
มีค่ามากกว่าศูนย์เสมอ (หรือไม่น้อยกว่าศูนย์) ตัวอย่าง:
รหัส | บันทึก |
---|---|
|
2. อายุการใช้งานของวัตถุ
คุณรู้อยู่แล้วว่าวัตถุถูกสร้างขึ้นโดยใช้new
ตัวดำเนินการ แต่วัตถุจะถูกลบอย่างไร พวกมันไม่มีอยู่ตลอดไป มีหน่วยความจำไม่เพียงพอสำหรับสิ่งนั้น
ในภาษาการเขียนโปรแกรมหลายภาษา เช่น C++ มีdelete
ตัวดำเนินการพิเศษสำหรับการลบวัตถุ แต่มันทำงานอย่างไรใน Java?
ใน Java ทุกอย่างถูกจัดเรียงแตกต่างกันเล็กน้อย Java ไม่มีตัวดำเนินการลบ นี่หมายความว่าวัตถุจะไม่ถูกลบใน Java หรือไม่ ไม่ พวกมันถูกลบไปแล้วแน่นอน มิฉะนั้น แอปพลิเคชัน Java จะหมดหน่วยความจำอย่างรวดเร็ว และจะไม่มีการพูดถึงโปรแกรมที่ทำงานโดยไม่หยุดชะงักเป็นเวลาหลายเดือน
ใน Java การลบออบเจกต์จะเป็นไปโดยอัตโนมัติทั้งหมด เครื่อง Java เองจัดการการลบวัตถุ กระบวนการนี้เรียกว่าการรวบรวมขยะ และกลไกที่รวบรวมขยะเรียกว่าตัวรวบรวมขยะ ( GC )
ดังนั้นเครื่อง Java รู้ได้อย่างไรว่าเมื่อใดควรลบวัตถุ
ตัวรวบรวมขยะแบ่งวัตถุทั้งหมดเป็น "เข้าถึงได้" และ "เข้าถึงไม่ได้" หากมีการอ้างอิงถึงวัตถุอย่างน้อยหนึ่งรายการ จะถือว่าเข้าถึงได้ หากไม่มีตัวแปรที่อ้างอิงถึงวัตถุ จะถือว่าวัตถุนั้นไม่สามารถเข้าถึงได้และถูกประกาศว่าเป็นขยะ ซึ่งหมายความว่าวัตถุนั้นสามารถลบทิ้งได้
ใน Java คุณไม่สามารถสร้างการอ้างอิงไปยังวัตถุที่มีอยู่ได้ — คุณสามารถกำหนดได้เฉพาะการอ้างอิงที่คุณมีอยู่แล้วเท่านั้น หากเราลบการอ้างอิงถึงอ็อบเจกต์ทั้งหมด มันจะสูญหายไปตลอดกาล
การอ้างอิงแบบวงกลม
ตรรกะนั้นฟังดูดีจนกระทั่งเราพบตัวอย่างง่ายๆ: สมมติว่าเรามีวัตถุสองชิ้นที่อ้างอิงถึงกันและกัน (เก็บข้อมูลอ้างอิงถึงกันและกัน) ไม่มีอ็อบเจกต์อื่นเก็บการอ้างอิงถึงอ็อบเจ็กต์เหล่านี้
ไม่สามารถเข้าถึงอ็อบเจ็กต์เหล่านี้ได้จากรหัส แต่ยังคงถูกอ้างอิง
นี่คือสาเหตุที่ตัวรวบรวมขยะแบ่งวัตถุออกเป็นที่เข้าถึงได้และเข้าถึงไม่ได้ แทนที่จะเป็น "อ้างอิง" และ "ไม่อ้างอิง"
วัตถุที่สามารถเข้าถึงได้
ประการแรก วัตถุที่มีชีวิต 100% จะถูกเพิ่มลงในรายการที่เข้าถึงได้ ตัวอย่างเช่น เธรดปัจจุบัน ( Thread.current()
) หรือ Console InputStream ( System.in
)
จากนั้นรายการของวัตถุที่สามารถเข้าถึงได้จะขยายเพื่อรวมวัตถุที่อ้างอิงโดยชุดเริ่มต้นของวัตถุที่สามารถเข้าถึงได้ จากนั้นจะขยายอีกครั้งเพื่อรวมวัตถุที่อ้างอิงโดยชุดที่ขยายนี้ และอื่นๆ
ซึ่งหมายความว่าหากมีวัตถุบางอย่างที่อ้างถึงกันเท่านั้น แต่ไม่มีวิธีเข้าถึงวัตถุเหล่านั้นจากวัตถุที่เข้าถึงได้ วัตถุเหล่านั้นจะถือว่าเป็นขยะและจะถูกลบ
3. การเก็บขยะ
การกระจายตัวของหน่วยความจำ
จุดสำคัญอีกประการหนึ่งที่เกี่ยวข้องกับการลบออบเจกต์คือการกระจายตัวของหน่วยความจำ หากคุณสร้างและลบอ็อบเจกต์อย่างต่อเนื่อง ในไม่ช้า หน่วยความจำจะถูกแยกส่วนอย่างหนัก: พื้นที่ของหน่วยความจำที่ถูกครอบครองจะกระจายไปกับพื้นของหน่วยความจำที่ไม่ได้ใช้งาน
เป็นผลให้เราเข้าสู่สถานการณ์ที่เราไม่สามารถสร้างวัตถุขนาดใหญ่ได้อย่างง่ายดาย (เช่น อาร์เรย์ที่มีองค์ประกอบเป็นล้าน) เนื่องจากไม่มีหน่วยความจำว่างจำนวนมาก กล่าวอีกนัยหนึ่ง อาจมีหน่วยความจำว่าง แม้จะมีจำนวนมาก แต่อาจไม่มีบล็อกหน่วยความจำว่างขนาดใหญ่ที่อยู่ติดกัน
การเพิ่มประสิทธิภาพหน่วยความจำ (จัดเรียงข้อมูล)
เครื่อง Java แก้ปัญหานี้ด้วยวิธีเฉพาะ ดูเหมือนว่า:
หน่วยความจำแบ่งออกเป็นสองส่วน วัตถุทั้งหมดถูกสร้างขึ้น (และถูกลบ) ในหน่วยความจำเพียงครึ่งเดียวเท่านั้น เมื่อถึงเวลาที่ต้องล้างช่องโหว่ในหน่วยความจำ วัตถุทั้งหมดในครึ่งแรกจะถูกคัดลอกไปยังครึ่งหลัง แต่พวกมันจะถูกคัดลอกติดกันเพื่อไม่ให้มีรู
กระบวนการมีลักษณะดังนี้:
ขั้นตอนที่ 1: หลังจากสร้างวัตถุ
ขั้นตอนที่ 2: ลักษณะของ "รู"
ขั้นตอนที่ 3: กำจัด "รู"
และนั่นเป็นเหตุผลที่คุณไม่จำเป็นต้องลบวัตถุ เครื่อง Java เพียงแค่คัดลอกออบเจกต์ที่เข้าถึงได้ทั้งหมดไปยังตำแหน่งใหม่ และเพิ่มพื้นที่หน่วยความจำทั้งหมดซึ่งออบเจ็กต์เคยถูกจัดเก็บไว้