假设我有一个带有注释的类,例如:
@MyConfig
class MyConfiguration {
@MyParameter
String parameter;
}
Run Code Online (Sandbox Code Playgroud)
如果我知道这个类的一个实例存在(例如,一个是在另一个线程中构造的),我如何才能在其他地方获得对该实例的引用。我试图通过它的@Annotation 找到该实例。
您不能简单地根据对象的类型或注释想象出对对象的引用,您也不应该真正想要这样做。造成这种情况的主要原因是垃圾收集——当对象超出范围时,JVM 会为您清理内存;如果您可以动态创建新引用,垃圾收集器将无法安全地清理任何内容,并且您会很快耗尽内存。
也就是说,您可以通过多种方法来构建您所描述的非常简单的功能,以便您可以按对象的类型查找对象。
Map最简单(也可以说是最好)的方法是使用 a (考虑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);
Run Code Online (Sandbox Code Playgroud)
您可能已经注意到这包含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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以确信,如果MyConfiguration实例存在,则可以通过其带注释的类型访问它annotationMap。
然而,正如我上面所暗示的,我怀疑这些对您来说都不是好的解决方案。真正的原因是因为注释根本不是为了让您引用实例而设计的;相反,它们的目的是让您在拥有某个实例后了解有关该实例的信息。那么我问你,为什么你认为你需要通过注释来查找对象?您可以使用另一种模式吗?
我怀疑您真正想要构建的是单例- 您希望运行时只有一个 实例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;
}
Run Code Online (Sandbox Code Playgroud)
这允许任何代码调用MyConfiguration.getInstance()并能够访问该实例。也就是说,单例通常被认为是不好的做法(尽管不如您所描述的那样)。理想情况下,您应该将配置实例传递给任何需要它的类或线程。显式传递引用,而不是依赖半神奇的缓存或像单例这样的全局状态,无疑是处理您所面临的问题的“正确”方法。