“嗨,阿米戈!”

“嗨,里希!”

“嗯,今天过得怎么样?”

“太棒了!今天 Bilaabo 告诉我递归,Ellie 告诉我弱引用和软引用。”

“她有没有告诉你有关幻影参考的事?”

“你是说PhantomReference吗?她提到了,但没有详细解释。”

“好,那我来填补这个空缺,希望你不要介意。”

“当然!我会很乐意听你的,Rishi!”

“太好了,那我开始了。”

“幻影引用是所有引用中最弱的。只有当一个对象除了幻影引用之外根本没有任何引用时它们才会起作用。”

幻影参考 - 1

“PhantomReference 用于复杂的对象删除过程。 当对象在 Java 机器之外做某事时,这可能是必要的,例如,它调用低级操作系统函数或将其状态写入文件或做其他非常重要的事情。”

“这是您可能如何使用它的示例:”

创建虚引用的示例
// 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——还有一个特殊的幻象引用队列。”

“为什么我们需要这个队列?”

“这就是我现在要告诉你的。”

“当你销毁一个由幻影引用持有的对象时,它会被销毁,但它并没有从内存中删除!你对此有何看法?!”

“那么,它是如何工作的?”

“这里有很多细微差别,所以我将从最简单的开始。”

“如果只剩下对一个对象的幻影引用,那么这就是它会发生的事情:”

"第 1 步。在下一次垃圾收集期间,将在对象上调用 finalize() 方法。但是,如果 finalize() 方法尚未被覆盖,则跳过此步骤,并立即执行第 2 步。"

第 2 步。在下一次垃圾收集期间,该对象被放置在一个特殊的幻像对象队列中。当对 PhantomReference 调用 clear() 方法时,它将从此队列中删除。”

“谁叫的?对象被删除了吧?”

“好吧,这个对象确实在我们的世界(Java 世界)中消亡了,但它并没有消失。它仍然是一个幻影——幻影对象的队列仍然持有对它的引用。我们非常仔细地引用了同一个ReferenceQueue传递给PhantomReference构造函数。”

“所以这个 ReferenceQueue 就像来世?”

“更像是一个幻影世界。”

“而一个幻影对象只能通过在它的幻影引用上调用 clear() 来删除。”

“这里是如何继续前面的例子:”

创建虚引用的示例
// 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();
}

“我知道这里正在发生一些事情。我什至几乎完全理解正在发生的事情。”

“但是你如何在实践中使用它呢?”

“这是一个更好的例子:”

创建虚引用的示例
// 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() 方法。仅此而已。幻影可以移动到一个更美好的世界。它不会再困扰我们。”

“太有趣了,但一切都成功了。”

“我们实际上是在跟踪一列垂死的对象,然后我们可以为每个对象调用一个特殊的方法。”

“但请记住,您不能调用对象本身的方法。 您无法获得对它的引用!PhantomReference 的 get() 方法始终返回 null。

“但是我们继承了 PhantomReference!”

“即使在 PhantomReference 的子类中,get() 方法也会返回 null。”

“所以我只是在构造函数中保存对对象的引用”

“啊。但这样的引用将是一个强引用,并且该对象永远不会在幻影队列中结束!”

“靠,行了,放弃吧,不行那就不行。”

“好的,很好。我希望你从今天的课程中学到了一些有价值的东西。”

“是的,有这么多新材料。我以为我已经知道了一切。谢谢你的课,Rishi。”

“不客气。就这样吧,去放松吧。但别忘了——我们今晚还有一节课。”