Java 37: Reference Types — Strong, Soft, Weak, Phantom
easy⏱ 5 mincoursejava
Strong references — the default
Any normal field or variable is a strong ref. As long as at least one strong ref exists, the object stays alive. Memory leaks = unintended strong references (e.g., a static list that never shrinks, or an inner class holding its outer instance).
Soft, Weak, Phantom
SoftReference: GC may clear if memory is tight — good for memory-sensitive caches. WeakReference: GC clears on next cycle if no strong refs remain — good for canonicalization maps (WeakHashMap). PhantomReference: never returns the referent; enqueued in a ReferenceQueue after finalization — used for reliable cleanup of native resources.
WeakHashMap<Key, Value> cache = new WeakHashMap<>();
cache.put(key, val);
// when `key` has no other strong refs, the entry vanishes on next GC
ReferenceQueue
When a Soft/Weak/Phantom ref is cleared, the JVM enqueues the Reference object (not the referent) into a ReferenceQueue you provided. You drain the queue to run cleanup logic. This is how DirectByteBuffer's off-heap memory is freed — Phantom ref + cleanup thread.
Build a Weak-ref cache
WeakCache<K, V> with put(k, v) and get(k). Internally use a Map to { valueHolder, strongKeyHolder } and expose a sweep() that simulates GC clearing entries whose external strong references (tracked by a symbol table) are gone. Test: insert 5 entries, drop 3 external refs, sweep, verify only 2 remain.
Cache eviction: LRU > Soft
SoftReference-based caches used to be popular but are now discouraged: the GC has no idea about your access patterns, so it may evict the hottest entries first. A bounded LRU cache (LinkedHashMap with accessOrder=true or Caffeine) almost always beats soft refs in practice.
Quiz: Why PhantomReference exists
What's the point if you can't get the referent? Reliable post-finalization cleanup. finalize() is deprecated and unreliable; phantom refs let you run cleanup after the object is truly unreachable, without resurrecting it. Used for native resource release in java.nio.