bob said:
Is it always technically correct to override the hashCode function like so:
@Override
public int hashCode() {
return 1;
}
Would it be potentially better if that was Object's implementation?
Maybe it would make sense to spell out what the contract
for hashCode() is. Well the contract is simply, the
following invariant should hold:
/* invariant that should hold */
if a.equals(b) then a.hashCode()==b.hashCode()
It should be noted that this does not imply:
/* not implied and thus not required by the invariant */
if a.hashCode()==b.hashCode() then a.equals(b)
It is also quite unlikely that a hashCode() would satisfy
the later, although the closer it comes to the later, the
better it works for HashMap, etc..
The default objects implementation of hashCode() matches
the default objects impementation of equals(). The default
objcts implementation of equals() is ==. And the default
objects implementation of hashCode() is
System.identityHashCode().
The System identity hash code is stored in the object
and generated by the system. It does not change during
GC although the internal object address might change
during GC. It is only 32bit although internal object
addresses might by 64bit with a corresponding JVM.
Returning a constant, any constant c not only 1, would be
technically correct correct for the default implementation
of the class object. Since it trivially satisfies the
invariant:
if a.equals(b) then c==c
is trivially true, since c==c is true. But it is not
better. Since you would get very degenerated HashMaps,
etc..
You need to override the hashhCode() when there is danger
that the invariant is not anymore satisified. This is
not the case when equals() is not overridden. So overriding
hashCode() just for fun when equals() is not overriden,
usually doesn't make sense. It will probably only slow
down the hashCode() calculation. So the following:
hashCode() = sum attr_i * c^i
Is not necessary. But it would be a possible way to go
when equals() were overriden in the following way:
equals(other) = and_i attr_i.equals(other.attr_i)
The above happens when you turn your object into a container
of other objects irrespective of the own object identity.
But beware if the container contains itself somewhere. This
is why we find in the code for Hashtable the following
complication:
public synchronized int hashCode() {
/*
* This code detects the recursion caused by computing the hash code
* of a self-referential hash table and prevents the stack overflow
* that would otherwise result. This allows certain 1.1-era
* applets with self-referential hash tables to work. This code
* abuses the loadFactor field to do double-duty as a hashCode
* in progress flag, so as not to worsen the space performance.
* A negative load factor indicates that hash code computation is
* in progress.
*/
Interestingly it will return a constant for the object when
it detects a loop. Maybe one could do better... Dunno
Bye