views:

497

answers:

8

I have two kinds of objects in my application where every object of one kind has exactly one corresponding object of the other kind.

The obvious choice to keep track of this relationship is a Map<type1, type2>, like a HashMap. But somehow, I'm suspicious. Can I use an object as a key in the Map, pass it around, have it sitting in another collection, too, and retrieve its partner from the Map any time?

After an object is created, all I'm passing around is an identifier, right? So probably no problem there. What if I serialize and deserialize the key?

Any other caveats? Should I use something else to correlate the object pairs, like a number I generate myself?

+12  A: 
  1. The key needs to implement .equals() and .hashCode() correctly
  2. The key must not be changed in any way that changes it's .hashCode() value while it's used as the key
  3. Ideally any object used as a key in a HashMap should be immutable. This would automatically ensure that 2. is always held true.
  4. Objects that could otherwise be GCed might be kept around when they are used as key and/or value.
Joachim Sauer
A: 

Any object can be a map key. The important thing here is to make sure that you override .equals() and .hashCode() for any objects that will be used as map keys.

The reason you do this is that if you don't, equals will be understood as object equality, and the only way you'll be able to find "equal" map keys is to have a handle to the original object itself.

You override hashcode because it needs to be consistent with equals. This is so that objects that you've defined as equals hash identically.

Steve B.
A: 

The failure points are the hashcode and equals functions. If they don't produce consistent and proper return values, the Map will behave strangely. Effective Java has a whole section on them and is highly, highly recommended.

sblundy
+7  A: 

I have two kinds of objects in my application where every object of one kind has exactly one corresponding object of the other kind.

This really sounds like a has-a relationship and thus could be implemented using a simple attribute.

Aaron Maenpaa
I agree. The rest of the question might still be useful for others, 'though. (or even for the @OP if that's not an alternative for some reason)
Joachim Sauer
@saua I agree with you. I just though I'd point out the applicability of attributes in this particular context.
Aaron Maenpaa
+1  A: 

You could use a standard Map, but doing so you will keep strong references to your objects in the Map. If your objects are referenced in another structure and you need the Map just to link them together consider using a WeakHashMap.

And BTW you don't have to override equals and hashCode unless you have to consider several instances of an object as equal...

pgras
+1  A: 

Can I use an object as a key in the Map, pass it around, have it sitting in another collection, too, and retrieve its partner from the Map any time?

Yes, no problem here at all.

After an object is created, all I'm passing around is an identifier, right? So probably no problem there. What if I serialize and deserialize the key?

That's right, you are only passing a reference around - they will all point to the same actual object. If you serialize or deserialize the object, that would create a new object. However, if your object implements equals and hashCode properly, you should still be able to use the new deserialized object to retrieve items from the map.

Any other caveats? Should I use something else to correlate the object pairs, like a number I generate myself?

As for Caveats, yes, you can't change anything that would cause the hashCode of the object to change while the object is in the Map.

Eric Petroelje
+2  A: 

It depends on the implementation of the map you choose:

  • HashMap uses equals() and hashCode(). By default (in Object) these are based on the object identity, which will work OK unless you serialize/deserialize. With a proper implementation of equals() and hashCode() based on the content of the object you will have no problems, as long as you don't modify it while it is a key in a hash map.

  • TreeMap uses compareTo(). There is no default implementation, so you need to provide one. The same limitations apply as for implementing hashCode() and equals() above.

starblue
A: 

You might consider Google Collection's BiMap.