« Salut Amigo ! »

« Salut, Rishi ! »

"Eh bien, comment était ta journée?"

"Génial ! Aujourd'hui, Bilaabo m'a parlé de la récursivité, et Ellie m'a parlé des références faibles et douces."

"Est-ce qu'elle t'a parlé de références fantômes ?"

« Parlez-vous de PhantomReference ? Elle l'a mentionné, mais ne l'a pas expliqué en détail.

"Super, alors j'espère que ça ne te dérangera pas si je comble ce vide."

« Bien sûr ! Je t'écouterai avec plaisir, Rishi !

"Génial. Alors je vais commencer."

"Les références fantômes sont les références les plus faibles de toutes. Elles n'ont d'effet que si un objet n'a aucune référence autre que des références fantômes."

PhantomReference - 1

"Une PhantomReference est utilisée dans une procédure de suppression d'objet complexe.  Cela peut être nécessaire lorsqu'un objet fait quelque chose en dehors de la machine Java, par exemple, il appelle des fonctions de système d'exploitation de bas niveau ou écrit son état dans un fichier ou fait autre chose de très important."

"Voici un exemple de la façon dont vous pourriez l'utiliser :"

Exemple de création de références fantômes
// 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));
}

"Je veux à nouveau attirer l'attention sur la dernière ligne. Non seulement l'objet x est transmis à la PhantomReference , mais également une file d'attente spéciale de références fantômes."

"Pourquoi avons-nous besoin de cette file d'attente ?"

"C'est ce que je vais te dire maintenant."

"Lorsque vous détruisez un objet détenu par une référence fantôme, il est détruit, mais il n'est pas supprimé de la mémoire ! Qu'en pensez-vous ?!"

« Alors, comment ça marche ?

"Il y a pas mal de nuances ici, donc je vais commencer par la plus simple."

"S'il ne reste que des références fantômes à un objet, voici ce qui lui arrivera :"

" Étape 1 . Lors de la prochaine récupération de place, la méthode finalize() sera appelée sur l'objet. Mais, si la méthode finalize() n'a pas été remplacée, cette étape est ignorée et l'étape 2 est exécutée immédiatement."

" Étape 2 . Lors de la prochaine récupération de place, l'objet est placé dans une file d'attente spéciale d'objets fantômes. Il sera supprimé de cette file d'attente lorsque la méthode clear() sera appelée sur la PhantomReference."

« Qui l'appelle ? L'objet a été supprimé, n'est-ce pas ? »

"Eh bien, l'objet est effectivement mort dans notre monde (le monde Java), mais il n'a pas disparu. Il reste comme un fantôme - la file d'attente d'objets fantômes contient toujours une référence à celui-ci. La même ReferenceQueue dont nous avons si soigneusement passé au constructeur PhantomReference ."

"Alors cette ReferenceQueue est comme l'au-delà ?"

"Plus comme un monde fantôme."

"Et un objet fantôme ne peut être supprimé qu'en appelant clear() sur sa référence fantôme."

"Voici comment continuer l'exemple précédent :"

Exemple de création de références fantômes
// 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();
}

"Je comprends qu'il se passe quelque chose ici. Je comprends presque exactement ce qui se passe."

« Mais comment l'utilisez-vous en pratique ? »

"Voici un meilleur exemple :"

Exemple de création de références fantômes
// 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));
}
Ce fil surveillera la file d'attente fantôme et en supprimera des objets
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();
Ceci est une classe qui hérite de PhantomReference et a une méthode 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!");
 }
}

"Nous avons fait trois choses ici."

« Tout d'abord, nous avons créé la classe PhantomInteger , qui hérite de PhantomReference < Integer >.

"Deuxièmement, cette classe a une méthode spéciale close (). La nécessité d'appeler cette méthode est ce qui a déclenché tout cela.

"Troisièmement, nous avons déclaré un thread spécial : referenceThread . Il attend dans une boucle jusqu'à ce qu'un autre objet apparaisse dans la file d'attente fantôme. Dès que cela se produit, le thread supprime l'objet de la file d'attente fantôme et appelle sa méthode close (). Et puis la méthode clear(). Et c'est tout. Le fantôme peut passer à un monde meilleur. Il ne nous dérangera plus dans le nôtre.

"Tellement intéressant, mais tout s'est bien passé."

"Nous suivons en fait une file d'attente d'objets mourants, puis nous pouvons appeler une méthode spéciale pour chacun d'eux."

"Mais rappelez-vous, vous ne pouvez pas appeler la méthode sur l'objet lui-même.  Vous ne pouvez pas y faire référence ! La méthode get() de PhantomReference renvoie toujours null. "

« Mais nous héritons de PhantomReference ! »

"Même à l'intérieur d'une sous-classe de PhantomReference, la méthode get() renvoie null."

"Donc j'enregistre juste une référence à l'objet dans le constructeur"

"Ah. Mais une telle référence serait une StrongReference, et l'objet ne se retrouvera jamais dans la file d'attente fantôme !"

"Bon sang. D'accord, abandonne. Si c'est impossible, alors c'est impossible."

"D'accord, bien. J'espère que vous avez appris quelque chose de précieux de la leçon d'aujourd'hui."

"Oui, il y avait tellement de nouveau matériel. Et je pensais que je savais déjà tout. Merci pour la leçon, Rishi."

"De rien. C'est tout, va te détendre. Mais n'oublie pas, nous avons une autre leçon ce soir."