"¡Hola, amigo!"

"¡Hola, Rishi!"

"Bueno, ¿cómo estuvo tu día?"

"¡Brillante! Hoy Bilaabo me habló sobre la recursividad, y Ellie me habló sobre las referencias débiles y blandas".

"¿Ella te habló de las referencias fantasma?"

"¿Estás hablando de PhantomReference? Ella lo mencionó, pero no lo explicó en detalle".

"Genial, entonces espero que no te importe si lleno este vacío".

"¡Por supuesto! ¡Te escucharé con gusto, Rishi!"

"Genial. Entonces empezaré".

"Las referencias fantasma son las referencias más débiles de todas. Solo tienen efecto si un objeto no tiene ninguna referencia que no sea referencia fantasma".

Referencia Fantasma - 1

"Una PhantomReference se usa en un procedimiento complejo de eliminación de objetos.  Esto puede ser necesario cuando un objeto hace algo fuera de la máquina Java, por ejemplo, llama a funciones del sistema operativo de bajo nivel o escribe su estado en un archivo o hace algo muy importante".

"Aquí hay un ejemplo de cómo podría usarlo:"

Ejemplo de creación de referencias fantasma
// 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));
}

"Quiero llamar la atención sobre la última línea nuevamente. No solo se pasa el objeto x a PhantomReference , también se pasa una cola especial de referencias fantasma".

"¿Por qué necesitamos esta cola?"

"Eso es lo que te voy a decir ahora".

"Cuando destruyes un objeto sostenido por una referencia fantasma, se destruye, ¡pero no se borra de la memoria! ¡¿Qué piensas de eso?!"

"Entonces, ¿cómo funciona eso?"

"Hay bastantes matices aquí, así que comenzaré con el más simple".

"Si solo quedan referencias fantasmas a un objeto, entonces esto es lo que le sucederá:"

" Paso 1 . Durante la próxima recolección de elementos no utilizados, se llamará al método finalize() en el objeto. Pero, si el método finalize() no se anuló, este paso se omite y el paso 2 se ejecuta inmediatamente".

" Paso 2. Durante la próxima recolección de elementos no utilizados, el objeto se coloca en una cola especial de objetos fantasma. Se eliminará de esta cola cuando se llame al método clear() en PhantomReference".

"¿Quién lo llama? El objeto fue eliminado, ¿verdad?"

"Bueno, el objeto sí murió en nuestro mundo (el mundo de Java), pero no ha desaparecido. Permanece como un fantasma: la cola de objetos fantasma todavía tiene una referencia a él. El mismo ReferenceQueue cuya referencia hemos buscado con tanto cuidado . pasado al constructor PhantomReference ".

"¿Así que esta ReferenceQueue es como el más allá?"

"Más como un mundo fantasma".

"Y un objeto fantasma solo se puede eliminar llamando a clear() en su referencia fantasma".

"Aquí se explica cómo continuar con el ejemplo anterior:"

Ejemplo de creación de referencias fantasma
// 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();
}

"Entiendo que algo está pasando aquí. Casi incluso entiendo exactamente lo que está pasando".

"¿Pero cómo usas esto en la práctica?"

"Aquí hay un mejor ejemplo:"

Ejemplo de creación de referencias fantasma
// 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));
}
Este hilo monitoreará la cola fantasma y eliminará objetos de ella.
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();
Esta es una clase que hereda PhantomReference y tiene un método 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!");
 }
}

"Hicimos tres cosas aquí".

"Primero , creamos la clase PhantomInteger , que hereda PhantomReference <Integer> ".

"Segundo, esta clase tiene un método close especial (). La necesidad de llamar a este método es lo que inició todo esto.

"Tercero, declaramos un subproceso especial: referenceThread . Espera en un bucle hasta que aparece otro objeto en la cola fantasma. Tan pronto como esto sucede, el subproceso elimina el objeto de la cola fantasma y llama a su método close (). Y luego el método clear(). Y eso es todo. El fantasma puede pasar a un mundo mejor. Ya no nos molestará en el nuestro".

"Tan interesante, pero todo salió bien".

"En realidad estamos rastreando una cola de objetos moribundos, y luego podemos llamar a un método especial para cada uno de ellos".

"Pero recuerda, no puedes llamar al método en el objeto mismo. ¡  No puedes obtener una referencia a él! El método get() de PhantomReference siempre devuelve nulo " .

"¡Pero heredamos PhantomReference!"

"Incluso dentro de una subclase de PhantomReference, el método get() devuelve un valor nulo".

"Así que solo guardo una referencia al objeto en el constructor"

"Ah. ¡Pero tal referencia sería una StrongReference, y el objeto nunca terminará en la cola fantasma!"

"Dang. Está bien, ríndete. Si es imposible, entonces es imposible".

"Está bien, bien. Espero que hayas aprendido algo valioso de la lección de hoy".

"Sí, había tanto material nuevo. Y pensé que ya lo sabía todo. Gracias por la lección, Rishi".

"De nada. Eso es todo, relájate. Pero no olvides que tenemos otra lección esta noche".