"Bună, Amigo!"

"Bună, Rishi!"

— Ei bine, cum a fost ziua ta?

"Genial! Astăzi, Bilaabo mi-a vorbit despre recursivitate, iar Ellie despre referințele slabe și blânde."

— Ți-a spus despre referințe fantomă?

"Vorbiți despre PhantomReference? Ea a menționat-o, dar nu a explicat-o în detaliu."

— Grozav, atunci sper că nu te deranjează dacă umplu acest gol.

"Desigur! O să te ascult cu plăcere, Rishi!"

— Grozav. Atunci voi începe.

"Referințele fantomă sunt cele mai slabe referințe dintre toate. Ele au efect numai dacă un obiect nu are nicio referință în afară de referințe fantomă."

PhantomReference - 1

„O referință Phantom este folosită într-o procedură complexă de ștergere a obiectelor.  Acest lucru poate fi necesar atunci când un obiect face ceva în afara mașinii Java, de exemplu, apelează funcții OS de nivel scăzut sau își scrie starea într-un fișier sau face altceva foarte important.”

„Iată un exemplu despre cum l-ați putea folosi:”

Exemplu de creare a referințelor fantomă
// 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));
}

„Vreau să atrag din nou atenția asupra ultimului rând. Nu numai că obiectul x este transmis la PhantomReference, ci și o coadă specială de referințe fantomă.”

„De ce avem nevoie de această coadă?”

— Asta am de gând să-ţi spun acum.

"Când distrugi un obiect ținut de o referință fantomă, acesta este distrus, dar nu este șters din memorie! Ce părere ai despre asta?!"

„Deci, cum funcționează?”

„Sunt destul de multe nuanțe aici, așa că voi începe cu cele mai simple.”

„Dacă rămân doar referințe fantomă la un obiect, atunci iată ce se va întâmpla cu el:”

" Pasul 1. În timpul următoarei colectări de gunoi, metoda finalize() va fi apelată pe obiect. Dar, dacă metoda finalize() nu a fost suprascrisă, atunci acest pas este omis, iar pasul 2 este executat imediat."

" Pasul 2. În timpul următoarei colectări de gunoi, obiectul este plasat într-o coadă specială de obiecte fantomă. Va fi șters din această coadă când metoda clear() este apelată pe PhantomReference."

"Cine îl cheamă? Obiectul a fost șters, nu?"

„Ei bine, obiectul a murit într-adevăr în lumea noastră (lumea Java), dar nu a dispărut. Rămâne ca o fantomă — coada de obiecte fantomă încă deține o referință la el. Aceeași ReferenceQueue a cărei referință o facem atât de atent transmis constructorului PhantomReference ."

„Deci această Codă de referință este ca viața de apoi?”

— Mai degrabă o lume fantomă.

„Și un obiect fantomă poate fi șters doar apelând clear() pe referința sa fantomă.”

„Iată cum să continuați exemplul anterior:”

Exemplu de creare a referințelor fantomă
// 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();
}

"Înțeleg că ceva se întâmplă aici. Aproape chiar înțeleg exact ce se întâmplă."

„Dar cum folosești asta în practică?”

„Iată un exemplu mai bun:”

Exemplu de creare a referințelor fantomă
// 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));
}
Acest thread va monitoriza coada fantomă și va elimina obiecte din ea
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();
Aceasta este o clasă care moștenește PhantomReference și are o metodă 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!");
 }
}

„Am făcut trei lucruri aici”.

„În primul rând, am creat clasa PhantomInteger , care moștenește PhantomReference < Integer >.”

„În al doilea rând, această clasă are o metodă specială de închidere (). Necesitatea de a apela această metodă este ceea ce a început toate acestea.

„În al treilea rând, am declarat un fir special: referenceThread . Așteaptă într-o buclă până când un alt obiect apare în coada fantomă. De îndată ce se întâmplă acest lucru, firul de execuție scoate obiectul din coada fantomă și apelează metoda sa close (). Și apoi metoda clear(). Și atât. Fantoma poate trece într-o lume mai bună. Nu ne va mai deranja în a noastră."

„Atât de interesant, dar totul a funcționat.”

„De fapt, urmărim o coadă de obiecte pe moarte și apoi putem apela la o metodă specială pentru fiecare dintre ele”.

"Dar amintiți-vă, nu puteți apela metoda pe obiectul în sine.  Nu puteți obține o referință la acesta! Metoda get() a PhantomReference returnează întotdeauna null. "

„Dar noi moștenim PhantomReference!”

„Chiar și în interiorul unei subclase a PhantomReference, metoda get() returnează null.”

„Deci salvez doar o referință la obiect în constructor”

"Ah. Dar o astfel de referință ar fi o StrongReference, iar obiectul nu va ajunge niciodată în coada fantomă!"

"Dang. Bine, renunță. Dacă este imposibil, atunci este imposibil."

"Bine, bine. Sper că ai învățat ceva valoros din lecția de azi."

"Da, a fost atât de mult material nou. Și am crezut că deja știu totul. Mulțumesc pentru lecție, Rishi."

"Cu plăcere. Gata, du-te relaxează-te. Dar nu uita - avem o altă lecție în seara asta."