假设我有一个带注释的类,例如:
@MyConfig
class MyConfiguration {
@MyParameter
String parameter;
}
如果我知道这个类的实例存在(例如,一个是在另一个线程中构造的),我怎样才能在其他地方获得对该实例的引用。我试图通过@Annotation找到实例。
答案 0 :(得分:4)
您不能简单地根据对象的类型或注释来构建对象的引用,也不应该真的想要。这样做的主要原因是垃圾收集 - 当对象超出范围时,JVM会为您清理内存;如果您可以动态创建新引用,垃圾收集器将无法安全地清理任何内容,并且您将快速耗尽内存。
这就是说有很多方法可以像你描述的那样简单地构建功能,这样你就可以按类型查找对象。
最简单(也称为最佳)的方法是使用Map
(考虑Guava的ClassToInstanceMap
)来简单地注册所需的实例。虽然你必须明确添加到地图,但在代码划分方面,这对你来说实际上会更加清晰。即使您将缓存行为设置为注释上的静态方法,或类似的东西,将构造与缓存分离也是一种很好的做法。
// somewhere accessible to both the constructing and accessing code, such as a
// public static field on the Annotation
Map<Class<? extends Annotation>,Object> annotationMap = new HashMap();
// wherever the instance is constructed
annotationMap.put(MyConfig.class, new MyConfiguration());
// wherever the instance is needed
MyConfiguration myConf = (MyConfiguration)annotationMap.get(MyConfig.class);
你可能已经注意到它保存了Object
个值,因为任何类在理论上都可以注释,所以我们必须显式转换。这将有效,假设您强制执行哪些类型插入到地图中,但它很脆弱。说实话,将注释与实例相关联的想法本身就很脆弱,所以这可能是你最不担心的事情。
如果你想确保最近构建的MyConfiguration
可以这样访问,你可以将上面的内容放在它的构造函数中,如下所示:
@MyConfig
class MyConfiguration {
public MyConfiguration() {
// note this is potentially dangerous, as this isn't finished constructing
// yet so be very cautious of this pattern, even though it might seem cleaner
annotationMap.put(MyConfig.class, this);
}
}
现在您可以确信,如果存在MyConfiguration
实例,则可以通过其注释类型从annotationMap
访问该实例。
正如我上面所暗示的那样,我怀疑这些都不适合你。而真正的原因是因为注释没有设计为所有让你引用实例;相反,它们意味着一旦你拥有一个实例就让你知道它。那么让我问你,为什么你认为你需要通过它的注释来查找对象?您可以使用其他模式吗?
我怀疑你真正想要构建的是Singleton - 你希望你的运行时只有一个MyConfiguration
实例,并且你希望所有代码都能轻松访问它。对此的标准模式是:
@MyConfig
class MyConfiguration {
private static MyConfiguration INSTANCE = null;
public static MyConfiguration getInstance() {
// note this is not thread-safe
// see the above link for several thread-safe modifications
if(INSTANCE == null) {
INSTANCE = new MyConfiguration();
}
return INSTANCE;
}
这允许任何代码调用MyConfiguration.getInstance()
并能够访问该实例。也就是说,单身人士通常被认为是不好的做法(尽管不如你所描述的那样)。理想情况下,您应该将配置实例传递给需要它的任何类或线程。明确地传递你的引用,而不是依赖于半神奇的缓存或像单身一样的全局状态,是处理你所面临的问题的“正确”方法。