如何在java中的注释字段中设置值?

Gok*_*bhu 3 java

我的注释类

@Target({java.lang.annotation.ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Base {
    int[] value();
}
Run Code Online (Sandbox Code Playgroud)

实际课程

public class Demo {
    @Base(1)
    public int var;
    public int var2;
    public void call() {
        InjectingClass.inject(this);
        System.out.print(var + "");
    }
}
Run Code Online (Sandbox Code Playgroud)

如何设置值onevar,而不是在var2

zap*_*apl 15

有了这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();
    }
}
Run Code Online (Sandbox Code Playgroud)

当你运行它打印

1
0
Run Code Online (Sandbox Code Playgroud)

它迭代声明的字段(即声明在此类中的所有字段,如果您希望这与超类的继承字段一起使用,您还必须扫描这些字段)

检查每个字段是否有注释,如果找到则将字段设置为注释中存在的值.

如果你想用一个CLASS或更简单的方法SOURCE(类是奇怪的,我会使用源或运行时)注释,你必须实现一个特殊的注释处理器类,在编译.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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在编译时基于注释分析.

因此,在运行时,注释基本上不存在,并且运行的代码基本上如下

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

由于这是所有直接普通的旧Java而不是反射,因此可以节省一些CPU周期.在大多数情况下,它很可能不会引人注意,但很多反射都会产生影响.

https://deors.wordpress.com/2011/10/31/annotation-generators/有一些更好的信息

还有第三种混合方法,即在运行时生成字节码.有了它,您将生成一个.class文件,该文件实现与.java文件大致相同.需要像https://github.com/cglib/cglib这样的字节码框架.由于您需要为Android生成.dex,因此该方法也不易与Android兼容.但我想我甚至已经看到过那个地方.