“สวัสดี อามีโก้!”

"สวัสดี ริชิ!"

“อืม วันนี้เป็นไงบ้าง”

"เยี่ยมมาก! วันนี้ Bilaabo บอกฉันเกี่ยวกับการเรียกซ้ำ และ Ellie บอกฉันเกี่ยวกับการอ้างอิงที่อ่อนแอและนุ่มนวล"

"เธอบอกคุณเกี่ยวกับการอ้างอิงผีหรือไม่"

"คุณกำลังพูดถึง PhantomReference ใช่ไหม เธอพูดถึงแต่ไม่ได้อธิบายรายละเอียด"

"เยี่ยมมาก ฉันหวังว่าคุณจะไม่ว่าอะไรถ้าฉันเติมเต็มช่องว่างนี้"

"แน่นอน! ฉันจะฟังคุณด้วยความยินดี Rishi!"

"เยี่ยมมาก งั้นฉันจะเริ่มแล้ว"

"การอ้างอิง Phantom เป็นการอ้างอิงที่อ่อนแอที่สุดของทั้งหมด มีผลเฉพาะเมื่อวัตถุไม่มีการอ้างอิงใด ๆ เลยนอกจากการอ้างอิง Phantom"

การอ้างอิงผี - 1

"PhantomReference ใช้ในขั้นตอนการลบออบเจกต์ที่ซับซ้อน  นี่อาจจำเป็นเมื่อออบเจ็กต์ทำบางอย่างนอกเครื่อง Java เช่น เรียกฟังก์ชันระบบปฏิบัติการระดับต่ำหรือเขียนสถานะลงในไฟล์ หรือทำอย่างอื่นที่สำคัญมาก"

"ต่อไปนี้เป็นตัวอย่างของวิธีที่คุณอาจใช้:"

ตัวอย่างการสร้าง Phantom Reference
// Special queue for phantom objects
ReferenceQueue<Integer> queue = new ReferenceQueue<Integer>();

// List of phantom references
ArrayList<PhantomReference<Integer>> list = new ArrayList<PhantomReference<Integer>>();

// Create 10 objects and add them to the list using phantom references
for ( int i = 0; i < 10; i++)
{
 Integer x = new Integer(i);
 list.add(new PhantomReference<Integer>(x, queue));
}

"ฉันต้องการดึงความสนใจไปที่บรรทัดสุดท้ายอีกครั้ง ไม่เพียงแต่ออบเจกต์ x จะถูกส่งไปยัง PhantomReference เท่านั้น แต่ยังมีคิวพิเศษของการอ้างอิงแบบ phantom ด้วย"

"ทำไมเราถึงต้องการคิวนี้"

“นั่นคือสิ่งที่ฉันจะบอกเธอในตอนนี้”

"เมื่อคุณทำลายวัตถุที่อ้างอิงถึงผี มันจะถูกทำลาย แต่มันไม่ได้ถูกลบออกจากความทรงจำ! คุณคิดยังไงกับเรื่องนั้น!"

"แล้วมันทำงานยังไง"

"มีความแตกต่างเล็กน้อยที่นี่ ดังนั้นฉันจะเริ่มต้นด้วยสิ่งที่ง่ายที่สุด"

"หากเหลือแต่การอ้างอิงแบบหลอนถึงวัตถุ สิ่งนั้นจะเกิดขึ้นกับวัตถุนั้น:"

" ขั้นตอนที่ 1ในระหว่างการรวบรวมขยะครั้งต่อไป เมธอด Finalize() จะถูกเรียกใช้บนออบเจกต์ แต่ถ้าเมธอด Finalize() ยังไม่ถูกแทนที่ ขั้นตอนนี้จะถูกข้ามไป และขั้นตอนที่ 2 จะถูกดำเนินการทันที"

" ขั้นตอนที่ 2ในระหว่างการรวบรวมขยะครั้งต่อไป ออบเจกต์จะถูกวางในคิวพิเศษของออบเจกต์หลอน มันจะถูกลบออกจากคิวนี้เมื่อเมธอด clear() ถูกเรียกบน PhantomReference"

"ใครโทรมา วัตถุถูกลบไปแล้วใช่ไหม"

"อืม วัตถุนั้นได้ตายไปแล้วจริงๆ ในโลกของเรา (โลกของ Java) แต่มันไม่ได้หายไป มันยังคงเป็นผีอยู่ — คิวของวัตถุหลอนยังคงมีการอ้างอิงถึงมัน ReferenceQueueเดียวกันกับที่เราอ้างอิงอย่างระมัดระวัง ผ่านไปยัง ตัวสร้าง PhantomReference "

"ดังนั้น ReferenceQueue นี้จึงเปรียบเสมือนชีวิตหลังความตาย"

"เหมือนโลกหลอนมากกว่า"

"และวัตถุหลอนสามารถลบได้โดยการเรียก clear() ในการอ้างอิงผีเท่านั้น"

"นี่คือวิธีดำเนินการต่อจากตัวอย่างก่อนหน้านี้:"

ตัวอย่างการสร้าง Phantom Reference
// Special queue for phantom objects
ReferenceQueue<Integer> queue = new ReferenceQueue<Integer>();

// List of phantom references
ArrayList<PhantomReference<Integer>> list = new ArrayList<PhantomReference<Integer>>();

// Create 10 objects and add them to the list using phantom references
for ( int i = 0; i < 10; i++)
{
 Integer x = new Integer(i);
 list.add(new PhantomReference<Integer>(x, queue));
}

// Call the garbage collector and hope it will listen to us :)
// It should destroy all phantom reachable objects and put them in the queue
// of phantoms
System.gc();

// Get all objects from the queue
Reference<? extends Integer>referenceFromQueue;
while ((referenceFromQueue = queue.poll()) != null)
{
 // Display the object on the screen
 System.out.println(referenceFromQueue.get());

 // Clear the reference
 referenceFromQueue.clear();
}

"ฉันเข้าใจว่ามีบางอย่างเกิดขึ้นที่นี่ ฉันเกือบจะเข้าใจว่าเกิดอะไรขึ้นด้วยซ้ำ"

"แต่คุณจะใช้สิ่งนี้ในทางปฏิบัติได้อย่างไร"

"นี่คือตัวอย่างที่ดีกว่า:"

ตัวอย่างการสร้าง Phantom Reference
// Special queue for phantom objects
ReferenceQueue<Integer> queue = new ReferenceQueue<Integer>();

// List of phantom references
ArrayList<PhantomInteger> list = new ArrayList<PhantomInteger>();

// Create 10 objects and add them to the list using phantom references
for ( int i = 0; i < 10; i++)
{
 Integer x = new Integer(i);
 list.add(new PhantomInteger (x, queue));
}
เธรดนี้จะตรวจสอบคิวผีและลบวัตถุออกจากคิว
Thread referenceThread = new Thread()
{
 public void run()
 {
  while (true)
  {
   try
   {
    // Get the new object from the queue. If there is no object, then we wait!
    PhantomInteger ref = (PhantomInteger)queue.remove();
    // Call the close method on it
    ref.close();
    ref.clear();
   }
   catch (Exception ex)
   {
    // Write errors to a log
   }
  }
 }
};
// Run the thread as a daemon
referenceThread.setDaemon(true);
referenceThread.start();
นี่คือคลาสที่สืบทอด PhantomReference และมีเมธอด close()
static class PhantomInteger extends PhantomReference<Integer>
{
 PhantomInteger(Integer referent, ReferenceQueue<? super Integer> queue)
 {
  super(referent, queue);
 }

 private void close()
 {
  System.out.println("Bad Integer totally destroyed!");
 }
}

"เราทำสามสิ่งที่นี่"

"อันดับแรก เราสร้าง คลาส PhantomIntegerซึ่งสืบทอดPhantomReference < Integer >"

"ประการที่สอง คลาสนี้มี เมธอด close () พิเศษ ความต้องการเรียกใช้เมธอดนี้คือสิ่งที่ทำให้ทั้งหมดนี้เริ่มต้นขึ้น

"ประการที่สาม เราประกาศเธรดพิเศษ: referenceThreadมันรอวนซ้ำจนกว่าออบเจกต์อื่นจะปรากฏในคิวผี ทันทีที่สิ่งนี้เกิดขึ้น เธรดจะลบออบเจ็กต์ออกจากคิวผีและเรียกใช้เมธอด close () จากนั้น วิธีการ clear() แค่นั้น ผีสามารถไปสู่โลกที่ดีกว่าได้ มันจะไม่รบกวนเราอีกต่อไป "

"น่าสนใจมาก แต่ทุกอย่างก็เรียบร้อย"

"เรากำลังติดตามคิวของวัตถุที่กำลังจะตาย และจากนั้นเราสามารถเรียกใช้วิธีการพิเศษสำหรับวัตถุแต่ละชิ้นได้"

"แต่จำไว้ว่า คุณไม่สามารถเรียกใช้เมธอดบนออบเจกต์ได้  คุณไม่สามารถรับการอ้างอิงถึงมันได้ เมธอด get() ของ PhantomReference จะคืนค่า null เสมอ "

"แต่เราสืบทอด PhantomReference!"

"แม้จะอยู่ในคลาสย่อยของ PhantomReference เมธอด get() จะคืนค่า null"

"ดังนั้นฉันจึงบันทึกการอ้างอิงถึงวัตถุในตัวสร้าง"

"อา แต่การอ้างอิงดังกล่าวจะเป็น StrongReference และวัตถุจะไม่มีวันจบลงในคิวหลอน!"

“แดง โอเค ยอมแพ้ ถ้ามันเป็นไปไม่ได้ มันก็เป็นไปไม่ได้”

"โอเค ดี ฉันหวังว่าคุณจะได้เรียนรู้สิ่งที่มีค่าจากบทเรียนวันนี้"

"ใช่ มีเนื้อหาใหม่ๆ มากมาย และฉันคิดว่าฉันรู้ทุกอย่างแล้ว ขอบคุณสำหรับบทเรียน ริชิ"

“ไม่เป็นไร แค่นี้แหละ ไปพักผ่อนเถอะ แต่อย่าลืมนะ เย็นนี้เรามีเรียนอีกคาบ”