java - 如何在带注释的字段中设置值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33971899/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set value in annotated field in java?
提问by Gokul Prabhu
My annotation Class
我的注释类
@Target({java.lang.annotation.ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Base {
int[] value();
}
Actual class
实际班级
public class Demo {
@Base(1)
public int var;
public int var2;
public void call() {
InjectingClass.inject(this);
System.out.print(var + "");
}
}
How can I set value one
to var
and not in var2
?
如何将值设置one
为var
而不是在var2
?
回答by zapl
With RUNTIME
generation, that's pretty simple
有了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();
}
}
When you run that it prints
当你运行它时它会打印
1
0
It's iterating over the declared fields (i.e. all fields where the declaration is in this class, If you want this to work with inherited fields from super classes you'd have to scan for those as well)
它迭代声明的字段(即声明在此类中的所有字段,如果您希望它与来自超类的继承字段一起使用,您还必须扫描这些字段)
Checks each field for the annotation and if found sets the field to the value present in the annotation.
检查注释的每个字段,如果找到,则将该字段设置为注释中存在的值。
When you want to do the same with a CLASS
or the simpler SOURCE
(class is oddand I would use either source or runtime) annotation you'd have to implement a special annotation processorclass that is called by the java compiler when compiling .java files that contain annotations you're interested in. In the next step you would generate a .java text source file that contains the code that does the injection. That code is then also compiled by the compiler and your Injector
class at runtime would simply call the generated code.
当您想对 aCLASS
或更简单的SOURCE
(类很奇怪,我将使用源代码或运行时)注释执行相同操作时,您必须实现一个特殊的注释处理器类,该类在编译 .java 文件时由 java 编译器调用包含您感兴趣的注释。在下一步中,您将生成一个 .java 文本源文件,其中包含执行注入的代码。然后该代码也由编译器编译,您的Injector
类在运行时将简单地调用生成的代码。
So all you need to do is to manage to write a class .java file like
所以你需要做的就是设法编写一个类 .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;
}
}
at compile time based on analysis of annotations.
在编译时基于对注释的分析。
So at runtime, the annotation is essentially not present and the code that runs is basically the following
所以在运行时,注解本质上是不存在的,运行的代码基本如下
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();
}
}
Since that's all straight forward plain old Java and not reflection you save some CPU cycles. It's most likely not noticeable in most cases but lots of reflection can have an impact.
由于这都是简单的老式 Java 而不是反射,因此您可以节省一些 CPU 周期。在大多数情况下,它很可能不会引起注意,但大量反射会产生影响。
https://deors.wordpress.com/2011/10/31/annotation-generators/has some more nice information
https://deors.wordpress.com/2011/10/31/annotation-generators/有一些更好的信息
There is also a third hybrid approach and that is bytecode generation at runtime. With that you would generate a .class file that implements roughly the same as the .java file. Needs a bytecode framework like https://github.com/cglib/cglib. That approach is also not easily compatible with Android since you need to generate .dex for Android. But I think I've seen even that somewhere.
还有第三种混合方法,即在运行时生成字节码。有了它,您将生成一个实现与 .java 文件大致相同的 .class 文件。需要像https://github.com/cglib/cglib这样的字节码框架。这种方法也不容易与 Android 兼容,因为您需要为 Android 生成 .dex。但我想我什至在某处看到过。