我的注释类
@Target({java.lang.annotation.ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Base {
int[] value();
}
实际课程
public class Demo {
@Base(1)
public int var;
public int var2;
public void call() {
InjectingClass.inject(this);
System.out.print(var + "");
}
}
如何将值one
设置为var
而不是var2
?
答案 0 :(得分:14)
生成RUNTIME
时,非常简单
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Set {
int value();
}
class Injector {
public static void inject(Object instance) {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Set.class)) {
Set set = field.getAnnotation(Set.class);
field.setAccessible(true); // should work on private fields
try {
field.set(instance, set.value());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
class Demo {
@Set(1)
public int var;
public int var2;
public void call(){
Injector.inject(this);
System.out.println(var);
System.out.println(var2);
}
}
public class AnnotationDemo {
public static void main(String[] args) {
new Demo().call();
}
}
运行时打印
1
0
它遍历声明的字段(即声明在此类中的所有字段,如果您希望它与超类中的继承字段一起使用,您也必须扫描这些字段)
检查每个字段是否有注释,如果找到则将字段设置为注释中的值。
如果你想对CLASS
或更简单的SOURCE
(类是odd并且我会使用源代码或运行时)注释你也必须这样做实现一个特殊的annotation processor类,在编译包含您感兴趣的注释的.java文件时由java编译器调用。在下一步中,您将生成一个包含代码的.java文本源文件。注射。该代码也由编译器编译,运行时Injector
类只调用生成的代码。
所以你需要做的就是设法写一个类.java文件,比如
class GeneratedInjector {
public static void inject(Object instance) {
if (instance instanceof Demo) {
injectDemo((Demo) instance);
}
}
public static void injectDemo(Demo demo) {
demo.var = 1;
}
}
在编译时基于注释分析。
因此,在运行时,注释基本上不存在,运行的代码基本上是以下
class GeneratedInjector {
public static void inject(Object instance) {
if (instance instanceof Demo) {
injectDemo((Demo) instance);
}
}
public static void injectDemo(Demo demo) {
demo.var = 1;
}
}
class Injector {
public static void inject(Object instance) {
GeneratedInjector.inject(instance);
}
}
class Demo {
public int var;
public int var2;
public void call(){
Injector.inject(this);
System.out.println(var);
System.out.println(var2);
}
}
public class AnnotationDemo {
public static void main(String[] args) {
new Demo().call();
}
}
由于这是所有直接普通的旧Java而不是反射,因此可以节省一些CPU周期。在大多数情况下,它很可能并不明显,但很多反思都会产生影响。
https://deors.wordpress.com/2011/10/31/annotation-generators/有一些更好的信息
还有第三种混合方法,即在运行时生成字节码。有了它,您将生成一个.class文件,该文件实现与.java文件大致相同。需要像https://github.com/cglib/cglib这样的字节码框架。由于您需要为Android生成.dex,因此该方法也不易与Android兼容。但我想我甚至已经在某处看到过。