1

I have a very large Set of Immutable Objects so I am thinking of assigning a unique hashcode to them at construction time.

private static int counter = Integer.MIN_VALUE;

private final double foo;
private final double bar;
private final int hashCode;

public MyImmutableObject(double foo, double bar)
{
    counter++;
    this.foo = foo;
    this.bar = bar;
    this.hashCode = counter;
}

@Override
public int hashCode()
{
    return this.hashCode;
}

   /**
    * Unneeded override of equals since its the same as in
    * Object, but shown for demonstration purposes. 
    */
@Override
public boolean equals(final Object obj)
{
    return this == obj;
}

This way, I can achieve the highest possible dispersity of keys, since I will have 232 unique keys. Of course, this also means that no two objects of this type will ever be equal, since an object will only be equal to itself.

edit: The Objects are also used as keys in Maps.

Is this possible to do? Are there hidden traps I missed?

1 Answer 1

4

Is this possible to do? Are there hidden traps I missed?

Thread safety, for one thing? You could use AtomicInteger to get round that, of course.

Then there's also the pointlessness of it, really. The built-in hash code is going to be pretty close to unique without you doing any extra work (and taking an extra 4 bytes per object). Given that you're not changing the meaning of equality (it's still basically reference equality) I can't see that there's any good reason to do this.

Sign up to request clarification or add additional context in comments.

14 Comments

That, and even with perfectly unique hash codes, hash tables will still have collisions -- since you're basically modding the hash codes by some value. There's no perfect way to avoid collisions, not even the way the OP describes. Given that, why add the extra complexity?
I always create hashCodes with Objects.hashCode() from guava and I assume I get some collisions because I notice about 20% improvement in a process that uses Set/Map with these objects. Not caching the value dramatically decreases performance according to my tests and profiling.
@AlexanderKaratarakis: I wasn't suggesting using Objects.hashCode - it's not clear what you'd hash here anyway, given that no fields are involved in the equality test. I'm suggesting removing the hashCode and equals entirely. Just use the built-in implementation, as you're only looking for reference equality.
Heh. ImmutableSet uses an open addressing approach which doesn't really have individual "buckets." That reduces memory consumption by ~60%, but for well-designed immutable element classes, it performs at least as well as HashSet. (Indeed, I'm working on a project to cut memory consumption by another 30-40%.) ImmutableMap uses a more traditional closed-addressing, linked-list approach, but it still saves ~20% on memory by omitting the cached hash code.
@AlexanderKaratarakis: If your "original implementation" uses a traditional equals method, then the code you've provided is completely unrepresentative. The distinction about whether you need value equality or reference equality is crucially important.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.