「こんにちは、アミーゴ!」

「やあ、リシ!」

「それで、今日はどうでしたか?」

「素晴らしいですね! 今日、Bilaabo は再帰について話してくれました。そして、Ellie は弱参照とソフト参照について教えてくれました。」

「彼女は幽霊に関する言及について話しましたか?」

「PhantomReference について話しているのですか? 彼女はそれについて言及しましたが、詳細は説明しませんでした。」

「わかりました。では、このギャップを埋めても構わないと思います。」

「もちろんです! 喜んで聞きますよ、リシ!」

「わかりました。それでは始めます。」

「ファントム参照は、すべての参照の中で最も弱い参照です。ファントム参照以外の参照がオブジェクトにまったくない場合にのみ効果があります。」

ファントムリファレンス - 1

「PhantomReference は、複雑なオブジェクトの削除手順で使用されます。 これは、オブジェクトが Java マシンの外部で何かを行う場合に必要になる場合があります。たとえば、低レベルの OS 関数を呼び出したり、その状態をファイルに書き込んだり、その他の非常に重要なことを行う場合です。」

「これを使用する例を次に示します。」

ファントム参照の作成例
// 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!");
 }
}

「私たちはここで 3 つのことを行いました。」

まず、PhantomReference < Integer >を継承するPhantomIntegerクラスを作成しました。

「第二に、このクラスには特別なclose () メソッドがあります。このメソッドを呼び出す必要があることが、すべての始まりです。

「3 番目に、特別なスレッド、referenceThreadを宣言しました。このスレッドは、別のオブジェクトがファントム キューに現れるまでループで待機します。これが発生するとすぐに、スレッドはファントム キューからオブジェクトを削除し、そのclose () メソッドを呼び出します。 「clear() メソッド。それだけです。ファントムはより良い世界に進むことができます。私たちの世界では、もう私たちを悩ませることはありません。」

「とても興味深いですが、すべてうまくいきました。」

「私たちは実際に死にかけているオブジェクトのキューを追跡しているので、それぞれに対して特別なメソッドを呼び出すことができます。」

「ただし、オブジェクト自体のメソッドを呼び出すことはできないことを覚えておいてください。 オブジェクトへの参照を取得することはできません。PhantomReference の get() メソッドは常に null を返します。

「しかし、私たちはPhantomReferenceを継承しています!」

「PhantomReference のサブクラス内であっても、get() メソッドは null を返します。」

「したがって、コンストラクター内のオブジェクトへの参照を保存するだけです。」

「ああ。でも、そのような参照は StrongReference であり、オブジェクトがファントム キューに入れられることはありません。」

「くそー。分かった、諦めろ。無理なら無理。」

「わかりました。今日のレッスンから何か価値のあることを学んでいただければ幸いです。」

「はい、新しい内容がたくさんありました。そして、私はすでにすべてを知っていると思っていました。レッスンをありがとう、リシ。」

「どういたしまして。以上です。リラックスしてください。でも忘れないでください。今夜は別のレッスンがあります。」