5

Here is my use case, I have an object that is logically equal to my HashMap key but not the same object (not ==). I need to get the actuall key object out of the HashMap so that i can synchronise on it. I am aware that i can iterate over the ketSet, but this is slow in comparison to hashing.

Looking through the java.util.HashMap implementation i see a getEntry(Object key) method that is exactly what i need. Any idea why this has not been exposed?

Can you think of any other way i can get the key out?

mR_fr0g
  • 8,462
  • 7
  • 39
  • 54
  • You could get it by reflection, and still use, if there is no other way around. – Geo Dec 09 '09 at 11:38
  • logically equal = equals method overwritten? HashMap always used equals and not ==. Using a mutable object as key class is in general discouraged. – dmeister Dec 09 '09 at 11:40
  • @Geo: I would be dubious about using reflection to obtain an object to synchronize on; partly because of performance concerns but mainly because explicit synchronization on non-constant objects is hard to grok anyway, never mind when you're obtaining that reference opaquely via reflection. It would likely be *very* hard to understand, follow and debug, making maintenance a nightmare. – Andrzej Doyle Dec 09 '09 at 11:42
  • yes, this is my problem. I have an object that myobject.equals(key) == true but myobject == key returns false. I need to get my hands on the key object. – mR_fr0g Dec 09 '09 at 11:44
  • @Geo: Getting at a method or object that's internal to the implementation of the HashMap is not a good idea. The internals of HashMap are not part of Java's public API and may change in a future version of Java, or HashMap may be implemented completely differently in another vendor's implementation of HashMap. – Jesper Dec 09 '09 at 13:43

6 Answers6

4

I think you would be better off putting in an extra layer of indirection on the value. The key should also be a "pure" value. Instead of:

Map<ReferenceObjectKey,Thing> map;

Use:

Map<ValueObjectKey,ReferenceObject<Thing>> map;
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • That may not necessarily be the problem here - for example, a `String` key would still lead to the same problems declared above (unless you `intern`ed all the Strings which is a bad idea); and I've never heard someone say that Strings are unsuitable map keys. – Andrzej Doyle Dec 09 '09 at 12:01
  • I don't follow. `String`s are value objects in my book. – Tom Hawtin - tackline Dec 09 '09 at 12:34
  • I'm saying that the problem will still exist with Strings and other value objects; the solution you've proposed won't resolve the issue (asides from the fact that the problem the querent posed is not the one that needs solving anyway). – Andrzej Doyle Dec 09 '09 at 14:11
3

I can't answer your actual question (why is the method not exposed) beyond the rather obvious, "because the authors decided not to expose it."

However your question leads me to believe that you have a rather strange synchronization scheme going on; from my understanding you're only trying to call it to get a canonical representation of equal objects for synchronization. That sounds like a really bad idea, as I noted in my comment to the question.

A better approach would be to revisit how and why you want to synchronize on these key objects, and rework your synchronization to be clearer and saner, preferably at a level higher up or by using an alternative approach altogether.

It might help if you posted a code snippet of what you want to do with this synchronization so that others can give their opinions on a cleaner way to implement it. One example would simply be to use a thread-safe map class (such as ConcurrentHashMap), if this is indeed what you're trying to achieve here.

Edit: Have a look at How To Ask Questions The Smart Way, in particular the bullet point I've linked as this is a classic example of that deficiency. It seems likely that your overall design is a bit off and needs to go in a different direction; so while you're stuck on this specific issue it's a symptom of a larger problem. Giving us the broader context will lead to you getting much better overall answers.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
2

Actually, the method the caller is asking for would have been useful. It was arguably a mistake that it, or something like it, was not included.

As it is, supposing you wish to increment the Integer value that's mapped from key "a" -- you end up having to do a hash lookup on "a" twice. Supposing you want to distinguish between a value being not present and the value being present but mapped to null -- again, two hash lookups.

In practice the world hasn't ended because of this, though.

Kevin Bourrillion
  • 40,336
  • 12
  • 74
  • 87
1

I stumbled upon this problem recently myself recently. When I boiled the problem down enough, it was that I was essentially using 2 different methods to associate data with the part of the key object that was used for determining equality.

  • With the value the key mapped to, via the Map
  • With the data contained with the key object, but that wasn't used in the .equals()/hashCode methods, via composition.

I was using a List in the key class to determine equality and hashcode, and there were 3 other fields in it - a boolean, and 2 Strings. In the end, I remade the map as a Map<List<String>, ...> and refactored the other 3 fields into their own class, then had the original class as a composition of the List and the new class. I felt that the code seemed better after this.

user968208
  • 11
  • 1
0

This sounds like a deeper problem you're heaving. Why do you need such a thing? Why is the key not unique to its object?

What do you mean with "so this i can synchronise on it" ?

Stefan Hendriks
  • 4,705
  • 5
  • 34
  • 43
  • I suspect what is desired is to have all calls for equal objects (i.e. that would map to the same key *within* the hash map), get access to a consistent object obstance for synchronization. The querent hasn't said why he wants this but it sounds like some kind of attempt to prevent two threads from modifying the mapping for a given key at once. – Andrzej Doyle Dec 09 '09 at 11:52
  • I think you're right. Using a ConcurrentHashMap could solve his problem, if the assumption about the problem is correct of course :) – Stefan Hendriks Dec 09 '09 at 12:15
-2

I'm sorry, but you seem to have a conceptual break here.

If your problem is that you "hold" an equivalent object (.equals() is true but == is false) to a key, and need to find the key, using the Object variant of get would not help you, because the only .equals that Object supports is identity (==).

What you need to do is to implement equals() and of course hashcode() in your key class.

This will make it trivial to obtain the entry.

CPerkins
  • 8,968
  • 3
  • 34
  • 47