2

Given an immutable object, it sometimes makes sense to cache its hashcode. Below is an example.

In the example, I realize that caching is more expensive than just recalculating the hashCode.

  public class ImmutableObject{
    final int immutableField1;
    final String immutableField2;

    //volatile? transient? WeakReference?
    private Integer cachedHashCode = null; 

    @Override
    public int hashCode() {
      Integer ret=cachedHashCode;
      if(ret == null) {
        ret = immutableField1;
        ret = 31 * ret + immutableField2.hashCode();
      }
      cachedHashCode = ret;
      return ret;
    }
    // constructor, equals, other methods...

  }

What modifiers does cachedHashCode need?

  • Volatile: Effective Java recommends using the volatile modifier here (how caching hashcode works in Java as suggested by Joshua Bloch in effective java?). As the class is immutable, under what conditions would non-strict execution ordering be dangerous? Is it solely to prevent redundant calculation of the hashCode?
  • Transient: If the hashcode is derived it is almost certainly cheaper to recalculate it than to serialize/deserialize it. Under what conditions would you want to serialize a hashcode?
  • WeakReference: If the class only has a couple fields, yet hashCode caching is still (somehow) worthwhile, the cached hashcode may add significantly to the memory footprint of each object. Should the cache then be a WeakReference? Will a WeakReference always take up at least as much space as the cached int?
Community
  • 1
  • 1
Andreas
  • 4,937
  • 2
  • 25
  • 35
  • 5
    Look at `String` source code as a best practice. Its cached `hash` is neither volatile, transient nor weakly referenced. – Alex Salauyou May 08 '15 at 22:17

1 Answers1

0

volatile:

Yes. This ensures that, after the assignment with a value, it is written to the memory and all other threads of your program will see it. Without volatile or a synchronized block there is no guarantee that the written value is visible by others. This magic is defined within the Java Memory Model.

transient:

Yes. However, makes only sense for classes marked as serializable. You never want to serialize something that is easy to recalculate. Maybe only if recaluculation takes a lot of effort, it could make sense. This is the typical space/time tradeoff decision.

WeakReference:

No. This adds more overhead. If you want to safe memory change to an int value. Add an extra flag or define a special number, for the "needs calculation" purpose.

cruftex
  • 5,545
  • 2
  • 20
  • 36