我比较习惯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中做同样的事情?我有一些顾虑:
>有人向我提到可能有多个类加载器,这可能会导致问题
> java中没有析构函数,那么如何从列表中删除引用?
>如果没有删除引用,这些对象什么时候被垃圾收集?
解决方法
简单的事情:除非使用非标准委托模式(使用自定义类加载器),否则多个类加载器不会导致问题.如果你确实有这样一个非标准的类加载器,你可以得到一个情况,即应用程序的不同部分使用不同版本的CPPClass类(每个版本来自不同的ClassLoader).这有各种问题(你可以从CPPClass到CPPClass获得一个ClassCastException转换!),但它不应该影响你的静态集合;每个CPPClass都有自己独立的集合.
接下来:不要从构造函数中将对象添加到集合中.从构造函数中泄漏此引用可能会导致内存模型问题.相反,您应该创建一个静态工厂方法来创建对象,然后将其单独添加到静态集合中.当然,该集合也应该是线程安全的.
最后,核心问题.如果每个对象不等于任何其他对象(即,如果您没有覆盖Object.equals),则可以使用WeakHashMap,将对象作为键.如果类确实覆盖了等号,则可以创建一个WeakReference的集合,您可以在方便的时候剪切(在插入时,在检索列表时等). WeakReference不会阻止它引用的对象被GCed – 它只会在GC发生之后从get返回null.
但是,如果我可以稍微进行一些编辑,那么像这样的“解决方案”通常会暗示一个定义不明确的对象生命周期,这会产生其他可维护性问题.如果你的对象实现了Closeable,或者对于使用它们的代码有类似的方式来声明它已经完成它可能会更好.