如何在Java中在运行时找到类的实例?

时间:2014-08-25 21:26:19

标签: java reflection

假设我有一个带注释的类,例如:

@MyConfig
class MyConfiguration {

    @MyParameter
    String parameter;
}

如果我知道这个类的实例存在(例如,一个是在另一个线程中构造的),我怎样才能在其他地方获得对该实例的引用。我试图通过@Annotation找到实例。

1 个答案:

答案 0 :(得分:4)

您不能简单地根据对象的类型或注释来构建对象的引用,也不应该真的想要。这样做的主要原因是垃圾收集 - 当对象超出范围时,JVM会为您清理内存;如果您可以动态创建新引用,垃圾收集器将无法安全地清理任何内容,并且您将快速耗尽内存。

这就是说有很多方法可以像你描述的那样简单地构建功能,这样你就可以按类型查找对象。

最简单(也称为最佳)的方法是使用Map(考虑GuavaClassToInstanceMap)来简单地注册所需的实例。虽然你必须明确添加到地图,但在代码划分方面,这对你来说实际上会更加清晰。即使您将缓存行为设置为注释上的静态方法,或类似的东西,将构造与缓存分离也是一种很好的做法。

// 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()并能够访问该实例。也就是说,单身人士通常被认为是不好的做法(尽管不如你所描述的那样)。理想情况下,您应该将配置实例传递给需要它的任何类或线程。明确地传递你的引用,而不是依赖于半神奇的缓存或像单身一样的全局状态,是处理你所面临的问题的“正确”方法。