Improving hashCode() to match equals()

M

Marco

In my NamedBitField class I define equals() to mean that 2
NamedBitFields are equal if all 3 of their fields are equal.

Any suggestions for improving my hashCode() definition? I
can improve its performance by caching the computed hashCode
in a transient field, sure, but can I improve the _way_ it's
computed?


class NamedBitField {

String name; // name of bit field
int startIndex; // where it starts
int length; // how many bits it occupies

pubic boolean equals(Object obj) {
if (this == obj)
return true;
if ( obj == null || this.getClass() != obj.getClass() )
return false;
NamedBitField other = (NamedBitField) obj;
return
this.name.equals(other.name) &&
this.startIndex == other.startIndex &&
this.length == other.length;
}

public int hashCode() {

// to make this symmetric with equals() I'd prefer to
// involve all 3 fields (name, startIndex and length)
// in the computation of the hash. But how?
//
// Here I'm simply reusing String.hashCode(), but the
// hashed String at least incorporates the other
// fields
return ((name + startIndex) + length).hashCode();
}
}


Marco
 
V

VisionSet

Marco said:
In my NamedBitField class I define equals() to mean that 2
NamedBitFields are equal if all 3 of their fields are equal.

Any suggestions for improving my hashCode() definition? I
can improve its performance by caching the computed hashCode
in a transient field, sure, but can I improve the _way_ it's
computed?


class NamedBitField {

String name; // name of bit field
int startIndex; // where it starts
int length; // how many bits it occupies

pubic boolean equals(Object obj) {
if (this == obj)
return true;
if ( obj == null || this.getClass() != obj.getClass() )
return false;
NamedBitField other = (NamedBitField) obj;
return
this.name.equals(other.name) &&
this.startIndex == other.startIndex &&
this.length == other.length;
}

public int hashCode() {

// to make this symmetric with equals() I'd prefer to
// involve all 3 fields (name, startIndex and length)
// in the computation of the hash. But how?
//
// Here I'm simply reusing String.hashCode(), but the
// hashed String at least incorporates the other
// fields
return ((name + startIndex) + length).hashCode();
}
}

public int hashCode() {

int const = 17;
int h = 13;
h = h * startIndex + const;
h = h * length + const;
h = h * name.hashCode() + cost;

return h;
}

Something like that, I believe, where 17 & 13 are different prime numbers,
but it isn't that important. It doesn't matter if h overflows.
 
C

Chris Smith

VisionSet said:
public int hashCode() {

int const = 17;
int h = 13;
h = h * startIndex + const;
h = h * length + const;
h = h * name.hashCode() + cost;

return h;
}

Something like that, I believe, where 17 & 13 are different prime numbers,
but it isn't that important. It doesn't matter if h overflows.

Sure, something like that. Except that, IIRC, const is an unused
reserved word in Java.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
M

Marco

That's great, thanks. This algorithm makes the following 2
objects would return different hash codes despite their
similarity...

p.name = "foobar"; p.startIndex = 2; p.length = 5;
q.name = "foobar"; q.startIndex = 5; q.length = 2;

I can see now that adding 17 ('const' variable) to the end
of each cumulative multiplication is essential. Looks fast
too. I may even benchmark it on my little 486 :)

I did have crazy thoughts about implementing hashCode() in
C and calling it through JNI. I guess the overhead in
dynamically linking and then marshalling arguments to a
native stack just isn't worth it for such a small piece of
code though.
IIRC, const is an unused reserved word in Java.

Thanks Chris. You're right. const is reserved.

Marco
 
T

Thinkit

VisionSet said:
public int hashCode() {

int const = 17;
int h = 13;
h = h * startIndex + const;
h = h * length + const;
h = h * name.hashCode() + cost;

return h;
}

Something like that, I believe, where 17 & 13 are different prime numbers,
but it isn't that important. It doesn't matter if h overflows.

You should really use 0x11 and 0xD, respectively. Unless you are
inputting bowling scores, there's no reason for decimal!
 
D

Derek Clarkson

Hi Marco,
I might be off the beam here but I noticed this piece of code in your
class:

What occured to me is that (if I read it correctly) you have a name of
"Fred", a startIndex = 1 and length = 12, would that produce the same
result as "Fred", 11 and 2 ?

If so would

String final delim = ":";
return (name + delim + startIndex + delim + length).hashCode();

be a better solution because it separates the fields so that the hashCode()
function can see the difference ?
 
M

Marco

Derek said:
If so would

String final delim = ":";
return (name + delim + startIndex + delim + length).hashCode();

be a better solution because it separates the fields so that the hashCode()
function can see the difference ?

Thanks Derek. You're right. Concatenating the numeric
fields eliminated their distinctiveness somewhat...

name = "Fred";
startIndex = 1; // if 11 then same hash code
length = 12; // if 2 then same hash code
// calls "Fred112".hashCode()
((name + startIndex) + length).hashCode();

Instead of pushing my object's state through
String.hashCode(), I'm now incorporating it into a series
of cumulative multiplications involving prime numbers as
recommended by an earlier post in this thread.

Marco
 
A

Alex Hunsley

Thinkit said:
You should really use 0x11 and 0xD, respectively. Unless you are
inputting bowling scores, there's no reason for decimal!

Why difference, at all, does it make whether he writes 13 or 0xD? It's
all the same to the bytecode that you end up with.
Also, there actually *is* a reason to use decimal - other coders who
come along later will more readily recognise 13 and 17 as prime numbers,
as opposed to 0x11 and 0xD. I don't know of many people that make a
habit of knowing what prime numbers are in hex.
(And, yes, you could convert it in your head back to decimal, but that's
just extra cognitive load and obfuscation.)

Ah, hold on, I've come across you before! You're the dude who thinks hex
is magically better than decimal somehow, and is on a mission to convert
the world!

http://makeashorterlink.com/?C2D351AD6

alex
 
A

Alex Hunsley

Alex said:
Why difference, at all, does it make whether he writes 13 or 0xD? It's
all the same to the bytecode that you end up with.
Also, there actually *is* a reason to use decimal - other coders who
come along later will more readily recognise 13 and 17 as prime numbers,
as opposed to 0x11 and 0xD. I don't know of many people that make a
habit of knowing what prime numbers are in hex.
(And, yes, you could convert it in your head back to decimal, but that's
just extra cognitive load and obfuscation.)

Ah, hold on, I've come across you before! You're the dude who thinks hex
is magically better than decimal somehow, and is on a mission to convert
the world!

http://makeashorterlink.com/?C2D351AD6

alex

Sorry, make that

http://makeashorterlink.com/?P2C412AD6

alex
 
K

Karl von Laudermann

You should really use 0x11 and 0xD, respectively. Unless you are
inputting bowling scores, there's no reason for decimal!

???
What an odd comment. As a long time aficionado of good programming
style, this is the first time I've ever heard this particular rule of
thumb. What's inherently better about using hex literals over decimal
literals in code? Personally, if I saw 0xD in that code, it would not
be immediately obvious that it was chosen for being prime.

In fact, for purely mathematical usage, I would say you should always
use decimal. I only use hex when dealing with low-level data concepts
such as bit masks and hardware flags; i.e. situations where knowing
the bit pattern of the data is more important than knowing its numeric
value.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top