11

I need a Map implementation that shares properties of both IdentityHashMap and WeakHashMap (reference equality instead of equals() and weak references on keys).

What implementation do you recommend (it has to work on Android)?

zduny
  • 2,481
  • 1
  • 27
  • 49
  • `IdentityHashMap, V>`? – fge Apr 07 '14 at 11:15
  • 1
    @fge I was thinking that but that won't remove the key from the map when it gets collected. – assylias Apr 07 '14 at 11:16
  • @assylias uh OK, I see the problem... Then a `WeakHashMap, V>` can do the trick (with `Equivalence.identity()`) but that requires Guava and inserting keys with `.wrap()` – fge Apr 07 '14 at 11:17
  • @fge Sounds like a reasonable solution - instead of guava it could simply be `class Wrapper { private final T t; public Wrapper(T t) { this.t = t;} public int hashcode() { return t.hashcode(); } public boolean equals(Object o) { return t == o; } }` – assylias Apr 07 '14 at 11:20
  • @assylias err... `return System.identityHashCode(t)`? ;) – fge Apr 07 '14 at 11:22
  • Anyway, back to the question, why do you need that exactly? – fge Apr 07 '14 at 11:24
  • @fge Well, it's complex: I'm implementing MVVM library for Android in parts similar to Microsoft's WPF. There is a thing called `DependencyProperty`, and containers of values for that properties are stored in a `Map`. They have to be removed from the map when `DependencyProperty` owner is collected... – zduny Apr 07 '14 at 11:29
  • @assylias It's nice solution but how do I find value for unwrapped element? – zduny Apr 07 '14 at 13:41
  • `public T get() { return t; }` ? – assylias Apr 07 '14 at 13:44
  • @assylias No but `Map`'s keys will be `Wrapper` so how can I find value for unwrapped key (`T`)? – zduny Apr 07 '14 at 13:46
  • 1
    `map.get(new Wrapper(t));` should work. – assylias Apr 07 '14 at 13:52
  • 5
    To roaming programmer that my read those comments - don't use fge's solution - it WON'T work. It may look like it does but it's broken. Here is why - `WeakHashMap` will point to `Equivalence.Wrapper` not `K` so keys will be removed when `Equivalence.Wrapper` is collected, not when collected is `K`. `Equivalence.Wrapper` might (and very likely will) be collected while `K` still does exist. – zduny May 05 '14 at 18:22
  • @mrpyo This can work if the `Wrapper extends WeakReference`. When GC collects K, it will collect `Wrapper` allowing `WeakHashMap` to remove `Map.Entry` as usual. To your last sentence, I'm unsure how `Equivalence.Wrapper` is likely to be collected when it can strongly reach `K` – Sgene9 Jun 04 '18 at 22:26
  • @Sgene9 `Equivalence.Wrapper` is likely to be collected because nothing holds strong reference to `Equivalence.Wrapper` - after all you are using `WeakReference>` in hash map keys and that map holds strong references to that `WeakReference>` and not `Equivalence.Wrapper`. But you are correct if `Equivalence.Wrapper` extended `WeakReference` it could probably work. – zduny Jun 05 '18 at 10:55
  • @mrpyo Oh, I was thinking the other way around. I was focused on how to automatically remove the key. You are right that the `Equivalence.Wrapper` is removed whether it extends `WeakReference` or not. – Sgene9 Jun 05 '18 at 13:30

1 Answers1

6

If you're suggesting Guava, then new MapMaker().weakKeys().makeMap() would do the job directly, since weakKeys uses reference equality for keys.

The documentation of weakKeys says:

Specifies that each key (not value) stored in the map should be wrapped in a WeakReference (by default, strong references are used). Warning: when this method is used, the resulting map will use identity (==) comparison to determine equality of keys, which is a technical violation of the Map specification, and may not be what you expect.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Thanks! And what about no Guava? – LppEdd Apr 09 '20 at 21:47
  • Following my first comment, in the scope of an IntelliJ Plugin, I've solved with two IdentityHashMap and a Disposable hierarchical system (offered by the platform). https://github.com/lppedd/idea-conventional-commit/blob/14ae62bf034a07467f465d41e728a9b03a2cfe16/src/main/kotlin/com/github/lppedd/cc/completion/CommitCompletionContributor.kt?fbclid=IwAR0Sly65RaInSLZKXRUPHfp-irHfVAQfRvCq4GTW0SW1dZHjE6ytYjC2-do#L157-L170 – LppEdd Apr 09 '20 at 23:21
  • If you don't want to use Guava, there is class [`WeakIdentityHashMap`](http://plumelib.org/plume-util/api/org/plumelib/util/WeakIdentityHashMap.html) in the [plume-util library](https://github.com/plume-lib/plume-util) does the same thing. – mernst Mar 18 '21 at 18:04