Java 具有不可变键的 WeakHashMap
Java WeakHashMap with immutable key
我想对将在内存中短时间存在的对象使用 WeakHashMap
。
每个对象都有一个 id(唯一的整数字段,它是来自数据库的主键),所以我的第一个想法是使用该字段作为对象的键。
但是,Integer 是不可变的,所以据我所知,哈希将产生另一个不可变的 Integer,因此只要任何其他不相关的对象指向它,该对象就不会被 GC。
有没有办法在 WeakHashMap
中使用整数键?
如您所说,WeakHashMap 不会提供所需的功能。 JavaDocs 声明如下
Thus care should be taken to ensure that value objects do not
strongly refer to their own keys, either directly or indirectly,
since that will prevent the keys from being discarded.
因此您可以实施 "WeakValueMap"。但这并不像听起来那么复杂。要么你简单地将 WeakReference 包装在类型定义中
Map<Integer, WeakReference<YourType>> cache ...
或者你围绕它实现一个包装器实现。
public class Cache<K, V> implements Map<K, V> {
private final Map<K, V> store = new HashMap<>();
// implement put, get, etc.
}
在 WeakHashMap
中使用 Integer
密钥不会阻止密钥被删除。
一旦不存在对放入 Map
的 same Integer
实例的引用,Integer
键可能会被垃圾回收。如果存在对 different Integer
实例的引用等于(即具有相同的数值)WeakHashMap
中的某个键,这不会阻止该键被自动删除。
请注意,您的 WeakHashMap
的值不得持有对密钥的强引用 - 否则密钥永远无法自动删除。因此,为避免这种情况,只需将值添加到 WeakHashMap
,如下所示:
Integer key = new Integer(someObject.getID());
weakMap.put(key,someObject);
现在,一旦您不再保留对 key
变量引用的 Integer
实例的引用,WeakHashMap
将自动删除它。
如果您 put
WeakHashMap
中的条目没有保留对键的引用(即 weakMap.put(new Integer(someObject.getID()),someObject)
),WeakHashMap
将能够自动删除它立即生效,我认为这不是您想要的。
在 WeakHashMap 中使用 Integer 作为键的一个问题是 Integer 可以被垃圾回收,而它映射到的值仍在内存中使用。
如果您想要将项目作为 HashMap 中的值而不阻止它们被垃圾收集,那么您应该将它们包装到 WeakReference 中并将它们用作常规映射中的值 Map<Integer, <WeakReference<Item>>
,也许有一种机制可以不时删除未使用的密钥。
或者,如果能够从它们的 id 中检索它们不是必需的,您可以使用 Items 本身作为 WeakHashMap 的键,并使用 Collections#newSetFromMap[=12= 从它们创建一个集合]
我想对将在内存中短时间存在的对象使用 WeakHashMap
。
每个对象都有一个 id(唯一的整数字段,它是来自数据库的主键),所以我的第一个想法是使用该字段作为对象的键。
但是,Integer 是不可变的,所以据我所知,哈希将产生另一个不可变的 Integer,因此只要任何其他不相关的对象指向它,该对象就不会被 GC。
有没有办法在 WeakHashMap
中使用整数键?
如您所说,WeakHashMap 不会提供所需的功能。 JavaDocs 声明如下
Thus care should be taken to ensure that value objects do not strongly refer to their own keys, either directly or indirectly, since that will prevent the keys from being discarded.
因此您可以实施 "WeakValueMap"。但这并不像听起来那么复杂。要么你简单地将 WeakReference 包装在类型定义中
Map<Integer, WeakReference<YourType>> cache ...
或者你围绕它实现一个包装器实现。
public class Cache<K, V> implements Map<K, V> {
private final Map<K, V> store = new HashMap<>();
// implement put, get, etc.
}
在 WeakHashMap
中使用 Integer
密钥不会阻止密钥被删除。
一旦不存在对放入 Map
的 same Integer
实例的引用,Integer
键可能会被垃圾回收。如果存在对 different Integer
实例的引用等于(即具有相同的数值)WeakHashMap
中的某个键,这不会阻止该键被自动删除。
请注意,您的 WeakHashMap
的值不得持有对密钥的强引用 - 否则密钥永远无法自动删除。因此,为避免这种情况,只需将值添加到 WeakHashMap
,如下所示:
Integer key = new Integer(someObject.getID());
weakMap.put(key,someObject);
现在,一旦您不再保留对 key
变量引用的 Integer
实例的引用,WeakHashMap
将自动删除它。
如果您 put
WeakHashMap
中的条目没有保留对键的引用(即 weakMap.put(new Integer(someObject.getID()),someObject)
),WeakHashMap
将能够自动删除它立即生效,我认为这不是您想要的。
在 WeakHashMap 中使用 Integer 作为键的一个问题是 Integer 可以被垃圾回收,而它映射到的值仍在内存中使用。
如果您想要将项目作为 HashMap 中的值而不阻止它们被垃圾收集,那么您应该将它们包装到 WeakReference 中并将它们用作常规映射中的值 Map<Integer, <WeakReference<Item>>
,也许有一种机制可以不时删除未使用的密钥。
或者,如果能够从它们的 id 中检索它们不是必需的,您可以使用 Items 本身作为 WeakHashMap 的键,并使用 Collections#newSetFromMap[=12= 从它们创建一个集合]