我想创建一个包含私有构造函数和静态工厂方法of
的类。我希望of
始终返回具有指定字段的类的现有实例,如果已创建此类实例但尚未由垃圾收集器收集。
我不想简单地保留Set
个实例,因为这会阻止实例被垃圾回收。我考虑过保留WeakHashMap
或Set<WeakReference>
,但这会将of
缩减到搜索范围,如果尺寸变大则会损害性能。
我想到的解决方案是这样的:
public final class Widget {
private static final Map<Integer, Set<Reference<Widget>>> map = new HashMap<>();
private final String string;
private final int value;
private Widget(String string, int value) {
this.string = string;
this.value = value;
}
public static Widget of(String string, int value) {
if (string == null)
throw new NullPointerException();
int hash = 31 * string.hashCode() + value;
Set<Reference<Widget>> set = map.get(hash);
if (set == null) {
set = new HashSet<>();
map.put(hash, set);
} else {
for (Iterator<Reference<Widget>> i = set.iterator(); i.hasNext();) {
Widget widget = i.next().get();
if (widget == null)
i.remove();
else if (widget.string.equals(string) && widget.value == value)
return widget;
}
}
Widget widget = new Widget(string, value);
set.add(new WeakReference<>(widget));
return widget;
}
static void tidy() {
for (Iterator<Set<Reference<Widget>>> i = map.values().iterator(); i.hasNext();) {
Set<Reference<Widget>> set = i.next();
for (Iterator<Reference<Widget>> i2 = set.iterator(); i2.hasNext();)
if (i2.next().get() == null)
i2.remove();
if (set.isEmpty())
i.remove();
}
}
}
此解决方案的问题在于您必须定期调用tidy()
方法,而我真的希望所有整理都能自动完成。
这个问题有简单或标准的解决方案吗?