Guava has the Equivalence
class, which does pretty much what you are asking for.
You can even wrap an Object in an Equivalence
to decorate an Object with a better hashCode() equals() implementation (e.g. if you want to use an Object with a bad equals() hashCode() as a Map key but don't have access to the sources)
Here's an example: arrays don't have proper implementations of equals() and hashCode(), but here's an Equivalence for char arrays:
private static final Equivalence<char[]> CHAR_ARRAY_EQUIV = new Equivalence<char[]>(){
@Override
protected boolean doEquivalent(char[] a, char[] b) {
return Arrays.equals(a, b);
}
@Override
protected int doHash(char[] chars) {
return Arrays.hashCode(chars);
}
};
Sample code:
final char[] first ={'a','b'};
final char[] second ={'a','b'};
Assert.assertFalse(first.equals(second));
Assert.assertFalse(first.hashCode() == second.hashCode());
final Wrapper<char[]> firstWrapped = CHAR_ARRAY_EQUIV.wrap(first);
final Wrapper<char[]> secondWrapped = CHAR_ARRAY_EQUIV.wrap(second);
Assert.assertTrue(firstWrapped.equals(secondWrapped));
Assert.assertTrue(firstWrapped.hashCode() == secondWrapped.hashCode());