18

I would like to know of a Map that works like a regular HashMap/Hashtable except it takes a function which returns the hashcode and performs the equality test rather than letting the HashMap use Object.hashCode/equals.

I cant use TreeMap because the objects do not implement Comparable and there is no stable way to handle the case of unequal objects. One cannot use System.identityHashCode because there is the potential for conflicts for objects that are not equal.

Ideally it would be great if the Map took a function in a similar way one can supply a custom Comparator to a TreeMap rather than letting the TreeMap cast parameters to Comparable.

The only way around this problem is to wrap each key and have the wrapper do the custom hashing/equals but surely therse a better way.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
mP.
  • 18,002
  • 10
  • 71
  • 105
  • 1
    "One cannot use System.identityHashCode because there is the potential for conflicts for objects that are not equal." That is pretty much part of a hash table. Hash collisions _do_ occur in every hash table implementation. – biziclop Mar 27 '11 at 23:43
  • Are the objects all the same type? Is there an impediment to having them implement Comparable? I imagine a solution can be set up by subclassing HashMap and overriding functions and passing in a function reference to them.. but it seems like a lot more effort than implementing Comparable. – roberttdev Mar 27 '11 at 23:43
  • This is a multipurpose q, many times unfortunately classes are not yours and you cannot alter them hence the need to supply a custom function to handle the hashing/equality test. – mP. Mar 28 '11 at 09:52
  • @biziclop, yes of course hash collisions occur but i would like the function to also handle equality tests, that way my function gets to say what is important in calculating the hash and equality. – mP. Mar 28 '11 at 09:53
  • Just to let you know I have exactly the same problem. I'm currently using a wrapper object with its own equals() and hashCode() methods, and the wrappers are taking up hundreds of megabytes of heap memory. I'm planning to take an open source implementation of HashMap and adapt it. – Michael Kay May 22 '14 at 18:00

5 Answers5

10

Did you consider a simple wrapper around the objects you would like to cache?

class Wrapper {
   YourObject object;

   public boolean equals(Object someOther) {
   ...
   }
   public int hashCode() {
   }
}
Jochen Bedersdorfer
  • 4,093
  • 24
  • 26
  • 1
    He said he did in his original post (you might want to re-read it), but I agree that it's likely the best solution and shouldn't have been discarded so quickly. – Hovercraft Full Of Eels Mar 27 '11 at 23:44
  • 2
    You could take this solution a step further and write a simple Map wrapper than uses this hash wrapper internally. The map wrapper could handle the wrapping and upwrapping of the objects as they are added or retrieved. – jt. Mar 27 '11 at 23:56
  • @jt problem is one also needs to handle keySet, entrySet their iterators etc which is not hard, but does amount to some work... – mP. Mar 28 '11 at 09:55
  • The problem with this is the additional amount of memory required and the additional performance required for constructing a new instance. The instance construction will also take place every time a value is retrieved from the map. You can't just use equals to compare also with the unwrapped key, since you won't know how your wrapped map handles the comparison - does it always compare the contained key to the queried key or does it also compare them the other way round. – SpaceTrucker Oct 17 '12 at 08:24
1

Plume-lib's WeakHasherMap does what you want: its constructor takes as an argument a Hasher object, which defines a hashCode() method and an equals() method.

(This existed at the time you wrote your question, but I only noticed your question now, 6.5 years after you asked it.)

Edit: I am a maintainer of plume-lib.

mernst
  • 7,437
  • 30
  • 45
1

As other answers suggest wrapping your objects with an object with the desired hashCode and equals is generally the best way to go. If on the rare case you want the function to be to use the original equals and hashCode implementation on Object there actually is IdentityHashMap for that very use case. However I appreciate the function you want is likely something than this.

William Jarvis
  • 347
  • 3
  • 6
0

When using TreeMap, the objects in the map are not required to implement Comparable.

Harv
  • 69
  • 2
  • You misundertand the problem that happens if i use TreeMap. If i supply my own custom Comparator how exactly do i compare unequal objects ? I cant use System.identityHashcode because another problem appears when there is a hashcode clash of unequal objects ! – mP. Mar 28 '11 at 09:57
  • You would implement the compare() method of the Comparator to consistently order the keys based on available public methods and/or fields of the key class. – Harv Mar 30 '11 at 03:09
  • Or just compare the hashcode as an int :). Too bad there's no IEqualityComparer – Hans Nov 05 '14 at 20:17
-1

I proposed an interface for such a "hash function" some time ago.

Now you need to take any implementation of a hash map (The OpenJDK one is GPL, for example) and modify all calls of hashCode() and .equals() with calls to this hash object. I did this once (many years ago), but it is not published.

Community
  • 1
  • 1
Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210