„Hallo, Amigo!“

„Hallo, Rishi!“

"Also, wie war dein Tag?"

„Genial! Heute hat mir Bilaabo von Rekursion erzählt und Ellie hat mir von schwachen und weichen Referenzen erzählt.“

„Hat sie dir von Phantomreferenzen erzählt?“

„Sprechen Sie von PhantomReference? Sie hat es erwähnt, aber nicht im Detail erklärt.“

„Großartig, dann hoffe ich, dass es Ihnen nichts ausmacht, wenn ich diese Lücke fülle.“

„Natürlich! Ich höre dir gerne zu, Rishi!“

„Großartig. Dann fange ich an.“

„Phantomreferenzen sind die schwächsten Referenzen von allen. Sie haben nur dann Wirkung, wenn ein Objekt überhaupt keine Referenzen außer Phantomreferenzen hat.“

PhantomReference – 1

„Eine PhantomReference wird in einem komplexen Objektlöschvorgang verwendet.  Dies kann erforderlich sein, wenn ein Objekt etwas außerhalb der Java-Maschine tut, z. B. es ruft Betriebssystemfunktionen auf niedriger Ebene auf oder schreibt seinen Status in eine Datei oder tut etwas anderes sehr Wichtiges.“

„Hier ist ein Beispiel dafür, wie Sie es verwenden könnten:“

Beispiel für die Erstellung von Phantomreferenzen
// 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));
}

„Ich möchte die Aufmerksamkeit noch einmal auf die letzte Zeile lenken. Objekt x wird nicht nur an die PhantomReference übergeben , sondern auch an eine spezielle Warteschlange mit Phantomreferenzen.“

„Warum brauchen wir diese Warteschlange?“

„Das werde ich dir jetzt sagen.“

„Wenn Sie ein Objekt zerstören, das von einer Phantomreferenz gehalten wird, wird es zerstört, aber nicht aus dem Speicher gelöscht! Was denken Sie darüber?!“

„Also, wie funktioniert das?“

„Hier gibt es einige Nuancen, also fange ich mit den einfachsten an.“

„Wenn nur Phantomverweise auf ein Objekt übrig bleiben, passiert Folgendes mit ihm:“

Schritt 1. Während der nächsten Garbage Collection wird die finalize()-Methode für das Objekt aufgerufen. Wenn die finalize()-Methode jedoch nicht überschrieben wurde, wird dieser Schritt übersprungen und Schritt 2 wird sofort ausgeführt.“

Schritt 2. Während der nächsten Garbage Collection wird das Objekt in eine spezielle Warteschlange von Phantomobjekten gestellt. Es wird aus dieser Warteschlange gelöscht, wenn die Methode „clear()“ für die PhantomReference aufgerufen wird.“

„Wer nennt es? Das Objekt wurde gelöscht, oder?“

„Nun, das Objekt ist in unserer Welt (der Java-Welt) tatsächlich gestorben, aber es ist nicht verschwunden. Es bleibt als Phantom – die Warteschlange der Phantomobjekte enthält immer noch eine Referenz darauf. Dieselbe ReferenceQueue, deren Referenz wir so sorgfältig ausgewählt haben an den PhantomReference -Konstruktor übergeben .“

„Diese ReferenceQueue ist also wie das Leben nach dem Tod?“

„Eher wie eine Phantomwelt.“

„Und ein Phantomobjekt kann nur gelöscht werden, indem man clear() für seine Phantomreferenz aufruft.“

„So setzen Sie das vorherige Beispiel fort:“

Beispiel für die Erstellung von Phantomreferenzen
// 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();
}

„Ich verstehe, dass hier etwas passiert. Ich verstehe fast sogar genau, was passiert.“

„Aber wie nutzt man das in der Praxis?“

„Hier ist ein besseres Beispiel:“

Beispiel für die Erstellung von Phantomreferenzen
// 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));
}
Dieser Thread überwacht die Phantomwarteschlange und entfernt Objekte daraus
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();
Dies ist eine Klasse, die PhantomReference erbt und über eine close()-Methode verfügt
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!");
 }
}

„Wir haben hier drei Dinge getan.“

„Zuerst haben wir die Klasse PhantomInteger erstellt, die PhantomReference < Integer > erbt.“

„Zweitens hat diese Klasse eine spezielle close ()-Methode. Die Notwendigkeit, diese Methode aufzurufen, hat alles ins Leben gerufen.

„Drittens haben wir einen speziellen Thread deklariert: referenceThread . Er wartet in einer Schleife, bis ein anderes Objekt in der Phantomwarteschlange erscheint. Sobald dies geschieht, entfernt der Thread das Objekt aus der Phantomwarteschlange und ruft seine Methode close () auf. Und dann die Methode „clear()“. Und das ist alles. Das Phantom kann in eine bessere Welt übergehen. Es wird uns in unserer Welt keine Probleme mehr bereiten.“

„So interessant, aber es hat alles geklappt.“

„Wir verfolgen tatsächlich eine Warteschlange sterbender Objekte und können dann für jedes von ihnen eine spezielle Methode aufrufen.“

„Aber denken Sie daran, dass Sie die Methode nicht für das Objekt selbst aufrufen können.  Sie können keinen Verweis darauf erhalten! Die get()-Methode der PhantomReference gibt immer null zurück.

„Aber wir erben PhantomReference!“

„Selbst innerhalb einer Unterklasse von PhantomReference gibt die Methode get() null zurück.“

„Also speichere ich einfach einen Verweis auf das Objekt im Konstruktor“

„Ah. Aber eine solche Referenz wäre eine StrongReference, und das Objekt wird niemals in der Phantomwarteschlange landen!“

„Verdammt. Okay, gib auf. Wenn es unmöglich ist, dann ist es unmöglich.“

„Okay, gut. Ich hoffe, Sie haben aus der heutigen Lektion etwas Wertvolles gelernt.“

„Ja, es gab so viel neues Material. Und ich dachte, ich wüsste schon alles. Danke für die Lektion, Rishi.“

„Gerne geschehen. Das war's, entspannen Sie sich. Aber vergessen Sie nicht – wir haben heute Abend noch eine Lektion.“