„Здрасти, Амиго!“

„Здрасти, Риши!“

— Е, How мина денят ти?

"Брилянтно! Днес Билаабо ми каза за рекурсия, а Ели ми каза за слаби и меки препратки."

— Тя каза ли ви за фантомни препратки?

"За PhantomReference ли говориш? Тя го спомена, но не го обясни подробно."

— Чудесно, тогава се надявам, че няма да имаш нищо против, ако запълня тази празнина.

"Разбира се! Ще те изслушам с удоволствие, Риши!"

"Чудесно. Тогава ще започна."

"Фантомните референции са най-слабите референции от всички. Те имат ефект само ако обектът няма ниHowви референции, различни от фантомни референции."

PhantomReference - 1

"PhantomReference се използва в сложна proceduresа за изтриване на обект.  Това може да е необходимо, когато даден обект прави нещо извън Java машината, например извиква функции на OS от ниско ниво or записва състоянието си във файл or прави нещо друго много важно."

„Ето пример за това How можете да го използвате:“

Пример за създаване на фантомни препратки
// 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 също и специална опашка от фантомни препратки.“

„Защо имаме нужда от тази опашка?“

— Това ще ти кажа сега.

"Когато унищожите обект, държан от фантомна препратка, той се унищожава, но не се изтрива от паметта! Какво мислите за това?!"

„Е, How става това?“

„Тук има доста нюанси, така че ще започна с най-простия.“

„Ако останат само фантомни препратки към обект, тогава ето Howво ще се случи с него:“

" Стъпка 1. По време на следващото събиране на отпадъци, методът finalize() ще бъде извикан на обекта. Но ако методът finalize() не е бил отменен, тази стъпка се пропуска и стъпка 2 се изпълнява незабавно."

" Стъпка 2. По време на следващото събиране на отпадъци обектът се поставя в специална опашка от фантомни обекти. Той ще бъде изтрит от тази опашка, когато методът clear() бъде извикан на PhantomReference."

"Кой го нарича? Обектът беше изтрит, нали?"

„Е, обектът наистина умря в нашия свят (света на Java), но не е изчезнал. Той остава като фантом – опашката от фантомни обекти все още съдържа препратка към него. Същият ReferenceQueue, чиято препратка ние толкова внимателно предава на конструктора PhantomReference ."

„Значи тази ReferenceQueue е като отвъдното?“

— По-скоро като призрачен свят.

„И фантомен обект може да бъде изтрит само чрез извикване на clear() на неговата фантомна референция.“

„Ето How да продължите предишния пример:“

Пример за създаване на фантомни препратки
// 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();
}

"Разбирам, че нещо се случва тук. Почти дори разбирам Howво точно се случва."

"Но How да използвате това на практика?"

„Ето по-добър пример:“

Пример за създаване на фантомни препратки
// 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!");
 }
}

— Тук направихме три неща.

„Първо създадохме класа PhantomInteger , който наследява PhantomReference < Integer >.“

„Второ, този клас има специален метод close (). Необходимостта да се извика този метод е това, което започна всичко това.

„Трето, декларирахме специална нишка: referenceThread . Тя чака в цикъл, докато друг обект се появи във фантомната опашка. Веднага щом това се случи, нишката премахва обекта от фантомната опашка и извиква своя метод close (). И след това методът clear(). И това е всичко. Фантомът може да се премести в един по-добър свят. Вече няма да ни притеснява в нашия."

„Толкова интересно, но всичко се получи.“

„Ние всъщност проследяваме опашка от умиращи обекти и след това можем да извикаме специален метод за всеки от тях.“

„Но не забравяйте, че не можете да извикате метода на самия обект.  Не можете да получите препратка към него! Методът get() на PhantomReference винаги връща нула.

„Но ние наследяваме PhantomReference!“

„Дори вътре в подклас на PhantomReference, методът get() връща нула.“

„Така че просто запазвам препратка към обекта в конструктора“

„Ах. Но такава препратка би била StrongReference и обектът никога няма да попадне във фантомната опашка!“

"Данг. Добре, откажи се. Ако е невъзможно, значи е невъзможно."

„Добре, добре. Надявам се, че сте научor нещо ценно от днешния урок.“

„Да, имаше толкова много нов материал. И си мислех, че вече знам всичко. Благодаря ти за урока, Риши.“

„Няма за Howво. Това е, отидете да се отпуснете. Но не забравяйте – имаме още един урок тази вечер.“