The Reference API

Reference API is a form of indirection. Quote: All problems in computer science can be solved by adding another level of indirection.

“All problems in computer science can be solved by adding another level of indirection.”

– David Wheeler, distinguished computer scientist and
professor of Computer Science at the University of Cambridge

Indirection is the ability to reference something using a name, reference, or container instead of the value itself. The Reference API classes can be used to add a level of indirection.

The Principle of Indirection

Indirection is a fundamental design principle, but what does it mean in practice?

Here are some examples of indirection:

  • We can pass a variable to a function via a parameter, but we can’t change the value of the original variable. However if we pass a pointer to the variable to the function then we can change the original variable.
  • We don’t access remote SOAP web services directly; rather we use a local proxy object to access the remote web service.
  • Within a database, a customer might have more than one address. The solution is to add a extra relation between customer and address (a one-to-many mapping).
  • Our application needs to display messages in multiple languages. Solution: we add keys to messages, and then resolve the translated language messages with those keys.

Each of these examples use an extra level of indirection to solve a problem.

The Reference API Classes

Let’s see how we can use a few standard Java classes to easily add an extra level of indirection to our objects. These classes are in the Reference API (java.lang.ref). This API contains an abstract Reference class and three concrete reference classes, each “softer” than the last. An instance of one of these subclasses encapsulates a single reference to a referent object.

The abstract base class is Reference. It defines methods for getting, clearing and enqueuing the reference.

The most important method is public T get(). This method returns the reference object’s referent. If the referent object has been cleared, then the method returns null.

The public void clear() method clears the reference object. This method can be invoked by application code. The garbage collector clears references directly, without invoking this method.

The three concrete reference classes are:

  • SoftReference – useful when implementing memory-sensitive caches.
  • WeakReference – useful for implementing canonicalizing mappings that do not prevent their keys (or values) from being reclaimed.
  • PhantomReference – used to schedule pre-mortem cleanup actions in a more flexible way than a finalize() method.

Using the Reference API

How do we use these classes? Instead of having a direct “hard” reference to our object, we create an intermediate Reference object that holds the reference to the actual object, and we hold a reference to this intermediate object. This Reference object creates an extra level of indirection.

“Okay, but why would we want to do that?”, you say. Good question. Hang in there a bit and I’ll answer it.

Usually when we create an object, we have a normal object reference referring to it. This is a strongly reachable object (or what I referred to earlier as a “hard” reference):

Employee emp = new Employee();

Until emp goes out of scope or we set it to null, we can access it directly in our code. This object is reachable by our code. Once it goes out of scope or set to null, the garbage collector can reclaim the memory, and the object disappears/becomes unreachable.

Let’s think about creating a cache to store commonly used objects. Let’s assume we have a CacheEntry class to model an entry in the cache. The internals of the CacheEntry class are not important here, other than it will hold a reference to some cacheable data. If we used strongly reachable CacheEntry objects, then we would have to manually manage the memory used by these entries. We’d have to keep an eye open for when we run low on heap memory and then delete some of the least recently used cache entries. This is a lot of work, and adds extra levels of complexity to our application.

// This is a strongly reachable "hard" reference.
// These entries would have to be manually managed.
CacheEntry entry = new CacheEntry(/* cacheable data */);

This is where SoftReferences come to the rescue. Let’s use a SoftReference to refer to the CacheEntry object. This adds an extra level of indirection and makes the CacheEntry object softly reachable. A SoftReference allows the garbage collector to automatically clear a CacheEntry object in response to memory demand. If we need to manually manage these entries as well, another part of our application could call the clear() method of the SoftReference when needed.

Read the following code:

// This is a softly reachable reference which is
// automatically managed by the garbage collector.
SoftReference<CacheEntry> softEntry = 
           new SoftReference<>(new CacheEntry());

// Accessing the object through the soft reference
CacheEntry entry = softEntry.get();
if (entry != null) {
    // The CacheEntry has not been cleared so we can
    // access and use it in some appropriate way.
} else {
    // The CacheEntry object has been cleared, so we can
    // create a new CacheEntry object if required.
}

So we can implement memory sensitive caches with very little effort. All softly reachable objects are guaranteed to be cleared by the garbage collector before the JVM throws an OutOfMemoryError.

If needed, we can also prevent the most recently used entries from being cleared by keeping strong referents to those entries. The garbage collector can then discard the remaining entries as required by memory demand.

Conclusion

I’ve only introduced the concept of indirection and softer references, and the problems it can solve.

If you find it interesting, I encourage you to read the API documentation. The Reference API is fairly complicated, and I’ve omitted the more esoteric details here.

I’m always interested in your opinion, so please leave a comment. Your feedback helps me write tips that help you.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.