"Chào, Amigo!"

"Chào, Rishi!"

"Chà, ngày hôm nay của bạn thế nào?"

"Tuyệt vời! Hôm nay Bilaabo nói với tôi về đệ quy, và Ellie nói với tôi về tham chiếu yếu và mềm."

"Cô ấy có nói với bạn về các tài liệu tham khảo ảo không?"

"Bạn đang nói về PhantomReference phải không? Cô ấy đã đề cập đến nó, nhưng không giải thích chi tiết."

"Tuyệt, vậy tôi hy vọng bạn sẽ không phiền nếu tôi lấp đầy khoảng trống này."

"Tất nhiên rồi! Tôi sẽ rất vui khi nghe bạn nói, Rishi!"

"Tuyệt. Vậy thì tôi bắt đầu."

"Tham chiếu ảo là tham chiếu yếu nhất trong tất cả. Chúng chỉ có hiệu lực nếu một đối tượng không có bất kỳ tham chiếu nào ngoài tham chiếu ảo."

PhantomReference - 1

"PhantomReference được sử dụng trong quy trình xóa đối tượng phức tạp.  Điều này có thể cần thiết khi một đối tượng thực hiện điều gì đó bên ngoài máy Java, ví dụ: nó gọi các chức năng hệ điều hành cấp thấp hoặc ghi trạng thái của nó vào một tệp hoặc thực hiện điều gì đó rất quan trọng."

"Đây là một ví dụ về cách bạn có thể sử dụng nó:"

Ví dụ về tạo tham chiếu ảo
// 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));
}

"Tôi muốn thu hút sự chú ý đến dòng cuối cùng một lần nữa. Đối tượng x không chỉ được chuyển đến PhantomReference mà còn có một hàng đặc biệt gồm các tham chiếu ảo."

"Tại sao chúng ta cần hàng đợi này?"

"Đó là những gì tôi sẽ nói với bạn bây giờ."

"Khi bạn hủy một đối tượng được giữ bởi một tham chiếu ảo, nó sẽ bị hủy, nhưng nó không bị xóa khỏi bộ nhớ! Bạn nghĩ sao về điều đó?!"

"Vậy làm thế nào mà làm việc?"

"Có khá nhiều sắc thái ở đây, vì vậy tôi sẽ bắt đầu với điều đơn giản nhất."

"Nếu chỉ còn lại các tham chiếu ảo đến một đối tượng, thì đây là điều sẽ xảy ra với nó:"

" Bước 1 . Trong lần thu gom rác tiếp theo, phương thức finalize() sẽ được gọi trên đối tượng. Tuy nhiên, nếu phương thức finalize() chưa bị ghi đè, thì bước này sẽ bị bỏ qua và bước 2 sẽ được thực thi ngay lập tức."

" Bước 2. Trong lần thu gom rác tiếp theo, đối tượng được đặt trong một hàng đợi đặc biệt gồm các đối tượng ảo. Nó sẽ bị xóa khỏi hàng đợi này khi phương thức clear() được gọi trên PhantomReference."

"Ai gọi nó? Đối tượng đã bị xóa, phải không?"

"Chà, đối tượng thực sự đã chết trong thế giới của chúng ta (thế giới Java), nhưng nó không biến mất. Nó vẫn như một bóng ma — hàng đợi của các đối tượng ảo vẫn giữ một tham chiếu đến nó. ReferenceQueue mà chúng ta đã tham chiếu rất cẩn thận được chuyển đến hàm tạo PhantomReference ."

"Vậy ReferenceQueue này giống như thế giới bên kia?"

"Giống như một thế giới ảo hơn."

"Và một đối tượng ảo chỉ có thể bị xóa bằng cách gọi clear() trên tham chiếu ảo của nó."

"Đây là cách tiếp tục ví dụ trước:"

Ví dụ về tạo tham chiếu ảo
// 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();
}

"Tôi hiểu rằng có điều gì đó đang xảy ra ở đây. Thậm chí tôi gần như hiểu chính xác chuyện gì đang xảy ra."

"Nhưng làm thế nào để bạn sử dụng điều này trong thực tế?"

"Đây là một ví dụ tốt hơn:"

Ví dụ về tạo tham chiếu ảo
// 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));
}
Chủ đề này sẽ giám sát hàng đợi ảo và loại bỏ các đối tượng khỏi nó
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();
Đây là lớp kế thừa PhantomReference và có phương thức 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!");
 }
}

"Chúng tôi đã làm ba điều ở đây."

"Đầu tiên, chúng tôi tạo lớp PhantomInteger kế thừa PhantomReference < Integer >."

"Thứ hai, lớp này có một phương thức close () đặc biệt. Nhu cầu gọi phương thức này là nguyên nhân khiến tất cả những điều này bắt đầu.

"Thứ ba, chúng tôi đã khai báo một luồng đặc biệt: referenceThread . Nó đợi trong một vòng lặp cho đến khi một đối tượng khác xuất hiện trong hàng đợi ảo. Ngay sau khi điều này xảy ra, luồng sẽ loại bỏ đối tượng khỏi hàng đợi ảo và gọi phương thức close () của nó. Và sau đó phương thức clear(). Vậy là xong. Bóng ma có thể chuyển sang một thế giới tốt đẹp hơn. Nó sẽ không còn gây rắc rối cho chúng ta trong thế giới của chúng ta nữa."

"Thật thú vị, nhưng tất cả đều thành công."

"Chúng tôi thực sự đang theo dõi một hàng các đối tượng sắp chết, và sau đó chúng tôi có thể gọi một phương thức đặc biệt cho từng đối tượng."

"Nhưng hãy nhớ rằng, bạn không thể gọi phương thức trên chính đối tượng đó.  Bạn không thể lấy tham chiếu đến nó! Phương thức get() của PhantomReference luôn trả về giá trị rỗng. "

"Nhưng chúng ta kế thừa PhantomReference!"

"Ngay cả bên trong một lớp con của PhantomReference, phương thức get() trả về null."

"Vì vậy, tôi chỉ lưu một tham chiếu đến đối tượng trong hàm tạo"

"À. Nhưng một tham chiếu như vậy sẽ là StrongReference và đối tượng sẽ không bao giờ kết thúc trong hàng đợi ảo!"

"Dang. Được rồi, từ bỏ đi. Nếu không thể, thì không thể."

"Được rồi, tốt. Tôi hy vọng bạn đã học được điều gì đó có giá trị từ bài học hôm nay."

"Vâng, có rất nhiều tài liệu mới. Và tôi nghĩ rằng tôi đã biết tất cả mọi thứ. Cảm ơn về bài học, Rishi."

"Không có gì. Vậy đó, đi nghỉ ngơi đi. Nhưng đừng quên - chúng ta có một bài học khác vào tối nay."