"안녕, 아미고!"

"안녕, 리시!"

"그럼 오늘 하루 어땠어?"

"훌륭합니다! 오늘 Bilaabo는 재귀에 대해 말했고 Ellie는 약하고 부드러운 참조에 대해 말했습니다."

"그녀가 유령 참조에 대해 말했습니까?"

"PhantomReference에 대해 말씀하시는 건가요? 그녀는 그것을 언급했지만 자세히 설명하지 않았습니다."

"좋아, 그럼 내가 이 공백을 메워도 상관없길 바래."

"물론이죠! 즐겁게 듣겠습니다, 리시!"

"좋습니다. 그럼 시작하겠습니다."

"팬텀 참조는 가장 약한 참조입니다. 개체에 팬텀 참조 이외의 참조가 전혀 없는 경우에만 효과가 있습니다."

PhantomReference - 1

"A PhantomReference는 복잡한 개체 삭제 절차에 사용됩니다.  개체가 Java 시스템 외부에서 작업을 수행할 때 필요할 수 있습니다. 예를 들어 하위 수준 OS 기능을 호출하거나 상태를 파일에 기록하거나 다른 매우 중요한 작업을 수행합니다."

"사용 방법에 대한 예는 다음과 같습니다."

팬텀 참조 생성 예
// 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로 전달될 뿐만 아니라 팬텀 참조의 특수 대기열도 전달됩니다."

"이 대기열이 필요한 이유는 무엇입니까?"

"그게 내가 지금 당신에게 말할 것입니다."

"팬텀 참조가 보유한 개체를 파괴하면 파괴되지만 메모리에서 삭제되지는 않습니다! 그것에 대해 어떻게 생각하세요?!"

"그래서 어떻게 작동합니까?"

"여기에는 약간의 뉘앙스가 있으므로 가장 간단한 것부터 시작하겠습니다."

"객체에 대한 팬텀 참조만 남아 있으면 다음과 같은 일이 발생합니다."

" 1단계 . 다음 가비지 수집 중에 개체에서 finalize() 메서드가 호출됩니다. 그러나 finalize() 메서드가 재정의되지 않은 경우 이 단계를 건너뛰고 2단계가 즉시 실행됩니다."

" 2단계 . 다음 가비지 수집 중에 객체는 팬텀 객체의 특수 대기열에 배치됩니다. PhantomReference에서 clear() 메서드가 호출되면 이 대기열에서 객체가 삭제됩니다."

"누가 불렀어? 개체가 삭제되었지?"

"글쎄, 객체는 실제로 우리 세계(Java 세계)에서 죽었지만 사라지지 않았습니다. 그것은 유령으로 남아 있습니다 . PhantomReference 생성자 에 전달되었습니다 ."

"그래서 이 ReferenceQueue는 사후 세계와 같은 건가요?"

"환상 세계에 가깝습니다."

"그리고 팬텀 객체는 팬텀 참조에서 clear()를 호출해야만 삭제할 수 있습니다."

"이전 예제를 계속하는 방법은 다음과 같습니다."

팬텀 참조 생성 예
// 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();
}

"나는 여기서 무슨 일이 일어나고 있다는 것을 이해합니다. 나는 무슨 일이 일어나고 있는지 거의 정확히 이해합니다."

"하지만 이것을 실제로 어떻게 사용합니까?"

"여기에 더 나은 예가 있습니다."

팬텀 참조 생성 예
// 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!");
 }
}

"우리는 여기서 세 가지 일을 했습니다."

"먼저 PhantomReference < Integer > 를 상속하는 PhantomInteger 클래스를 만들었습니다 ."

"둘째, 이 클래스에는 특수한 close () 메서드가 있습니다. 이 메서드를 호출해야 할 필요성이 이 모든 작업을 시작하게 했습니다.

"셋째, 우리는 특수 스레드인 referenceThread를 선언했습니다. 이 스레드는 팬텀 큐에 다른 개체가 나타날 때까지 루프에서 대기합니다. 이런 일이 발생하는 즉시 스레드는 팬텀 큐에서 개체를 제거하고 해당 close () 메서드를 호출합니다. 그런 다음 clear() 방법. 그게 다야. 팬텀은 더 나은 세상으로 이동할 수 있습니다. 더 이상 우리를 괴롭히지 않을 것입니다."

"흥미롭지만 모든 것이 해결되었습니다."

"우리는 실제로 죽어가는 개체의 대기열을 추적하고 있으며 각각에 대해 특별한 메서드를 호출할 수 있습니다."

"하지만 기억하세요. 개체 자체에서 메서드를 호출할 수 없습니다. 개체  에 대한 참조를 얻을 수 없습니다! PhantomReference의 get() 메서드는 항상 null을 반환합니다. "

"하지만 우리는 PhantomReference를 물려받았습니다!"

"PhantomReference의 하위 클래스 내부에서도 get() 메서드는 null을 반환합니다."

"그래서 생성자에 개체에 대한 참조를 저장합니다."

"아. 하지만 그런 참조는 StrongReference가 될 것이고 개체는 팬텀 대기열에 절대 들어가지 않을 것입니다!"

"댕. 알았어, 포기해. 불가능하면 불가능."

"좋아, 좋아. 오늘 수업에서 귀중한 것을 배웠기를 바란다."

"예, 새로운 자료가 너무 많았습니다. 그리고 이미 모든 것을 알고 있다고 생각했습니다. 강의 감사합니다, Rishi."

"천만에요. 그게 다예요. 긴장을 푸세요. 하지만 잊지 마세요. 오늘 저녁에 또 다른 수업이 있습니다."