我更习惯C ++。要获取类的所有实例的列表(这是一个可以由用户扩展的库类),我通常有一个静态容器,其中包含对这些对象的所有引用:
#include <list>
class CPPClass;
class CPPClass {
public:
CPPClass() {
objList.push_back(this);
}
~CPPClass() {
objList.remove(this);
}
private:
static std::list<CPPClass *> objList;
};
std::list<CPPClass *> CPPClass::objList;
我应该如何在Java中做同样的事情?我有一些顾虑:
答案 0 :(得分:4)
简单的事情:除非使用非标准委托模式(使用自定义类加载器),否则多个类加载器不会导致问题。如果你确实有这样一个非标准的类加载器,你可以得到一个情况,即应用程序的不同部分使用不同版本的CPPClass
类(来自不同ClassLoader的每个版本)。这有各种问题(您可以从ClassCastException
到CPPClass
进行CPPClass
投射!),但它不应该影响您的静态集合;每个CPPClass
都有自己独立的集合。
下一步:不要从构造函数中将对象添加到集合中。从构造函数中泄漏this
引用可能会导致内存模型问题。相反,您应该创建一个静态工厂方法来创建对象,然后将其单独添加到静态集合中。当然,该集合也应该是线程安全的。
最后,核心问题。如果每个对象不等于任何其他对象(即,如果您没有覆盖Object.equals
),则可以使用WeakHashMap,将对象作为键。如果类覆盖equals
,则可以创建WeakReference的集合,您可以在方便的时候剪切(插入时,检索列表等)。 WeakReference不会阻止它引用的对象被GCed - 它会在GC发生之后从null
返回get
。
但是,如果我可以稍微进行一些编辑,那么像这样的“解决方案”通常会暗示一个定义不明确的对象生命周期,这会产生其他可维护性问题。如果您的对象实现Closeable
或者使用它们的代码具有类似的方式来声明它已完成它们可能会更好。
答案 1 :(得分:1)
不是存储对象的引用,而是将WeakReference存储到对象中 - 这样,如果WeakReference是唯一保留的引用,则垃圾收集器将释放该对象。
答案 2 :(得分:0)
您确实可以将列表设为静态,只需确保您也正确初始化它。
List<CPPClass> objlist;
static {
objlist = new List<CPPClass>();
}
或类似的东西应该这样做。
如果不删除引用,它将永远不会收集垃圾,因为垃圾收集器将假定该对象仍在使用中。
有些东西看起来有点像析构函数:方法finalize
。但是因为这个方法只是由垃圾收集器调用而你自己不能使用它,所以对你没用。