6

假设,我有很多类,它们是使用 Java 反射构造的(出于某种原因)。现在我需要将值后注入到字段中,这些字段用@PostInject.

public class SomeClass {
  @PostInject
  private final String someString = null;

  public void someMethod() {
    // here, someString has a value.
  }
}

我的问题是:使用反射设置字段的快速方法是什么?
请记住,我需要在很多课程上经常这样做,这就是为什么性能是相关的。

这个伪代码显示了我会凭直觉做什么:

  • 获取类的所有字段
    clazz.getFields();
  • 检查,用 @PostInject 注释
    eachField.getAnnotation(PostInject.class);
  • 使这些字段可访问
    eachAnnotatedField.setAccessible(true);
  • 将它们设置为某个值
    eachAnnotatedField.set(clazz, someValue);

恐怕获得所有领域是最慢的事情。
当我从一开始就知道时,我可以得到一个领域吗?

注意:我不能只让类实现一些接口,这将允许使用方法设置字段。我需要POJO。

NOTE2:为什么我想要后字段注入:从 API 用户的角度来看,必须可以使用 final 字段。此外,当API先验不知道字段的类型和数量时,不可能使用接口来实现字段初始化。

NOTE2b:从用户的角度来看,最终的合同没有被破坏。它保持最终状态。首先,一个字段被初始化,然后它不能被改变。顺便说一句:有很多 API 使用这个概念,其中之一是 JAXB(JDK 的一部分)。

4

5 回答 5

7

在构建对象并保存您在对象本身中获得的注释字段集或通过将类的单独映射保存到注释字段集之后执行步骤 1 到 3 怎么样?

然后,当您需要更新对象中的注入字段时,从对象或单独的映射中检索集合并执行步骤 4。

于 2009-10-28T12:16:20.013 回答
1

另一种选择,正如您所说,您从一开始就知道几个相关领域,是只询问那些领域或方法。

示例:参见java /lang/Class.htmlgetDeclaredMethod中的或getDeclaredField

于 2009-10-28T12:31:01.113 回答
1

不知道它是否有任何好处,但这个项目看起来会做你想做的事。引用:

一组与使用类及其字段相关的反射实用程序和杂项实用程序,它们没有与 java 1.5 和泛型兼容的依赖项。

实用程序缓存反射数据以实现高性能操作,但使用弱/软缓存来避免保持打开的 ClassLoaders 并导致缓存永久存在于内存中。支持使用您自己的缓存机制覆盖的能力。

于 2009-10-28T12:40:04.063 回答
0

您可以利用允许在对象构造上注入依赖项的现有框架。例如Spring 允许使用 aspectj 编织来做到这一点。一般的想法是,您在 spring 级别定义 bean 依赖项并标记目标类以建议它们的对象创建。实际的依赖解析逻辑直接注入到类字节码中(可以使用编译时或加载时编织)。

于 2009-10-28T13:00:41.393 回答
0

使用反射做任何事情的最快方法是尽可能缓存实际的反射 API 类。例如,我最近制作了一个又一个动态 POJO 操纵器,我相信这是每个​​人最终都会在某些时候做的事情之一,这使我能够做到这一点:

Object o = ...
BeanPropertyController c = BeanPropertyController.of(o);

for (String propertyName : c.getPropertyNames()) {
        if (c.access(propertyName) == null && 
            c.typeOf(propertyName).equals(String.class)) {
                c.mutate(propertyName, "");
        }
}

它的工作方式是它基本上有一个控制器对象,它延迟加载 bean 的所有属性(注意:涉及一些魔法),然后只要实际的控制器对象还活着,就可以重用它们。我只能说,通过自己保存 Method 对象,我设法把那个东西变成了一个该死的快东西,我为此感到非常自豪,甚至考虑发布它,假设我可以设法解决版权等问题。

于 2009-10-28T19:55:10.853 回答