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

如何在java中设置带注释字段的值?,java,Java,我的注释类 @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() { In

我的注释类

@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

使用
运行时
生成,这非常简单

@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
它在声明的字段上进行迭代(即声明位于此类中的所有字段,如果您希望它与从超类继承的字段一起工作,您还必须扫描这些字段)

检查注释的每个字段,如果找到,则将字段设置为注释中的值

当您想要对
或更简单的
(类是,我将使用源或运行时)注释执行相同操作时,您必须实现一个特殊的类,该类在编译包含您感兴趣的注释的.java文件时由java编译器调用。在下一步中,您将生成一个.java文本源文件,其中包含执行注入的代码。然后,该代码也由编译器编译,您的
Injector
类在运行时只需调用生成的代码

因此,您需要做的就是编写一个class.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周期。在大多数情况下,这很可能不明显,但大量的反思会产生影响

有更多的好消息


还有第三种混合方法,即在运行时生成字节码。这样,您将生成一个.class文件,该文件的实现与.java文件大致相同。需要像这样的字节码框架。这种方法也不容易与Android兼容,因为您需要为Android生成.dex。但我想我在什么地方都见过。

嗯?你不是已经这么做了吗?当前代码有什么问题?很抱歉没有具体说明。我没有实现InjectingClass。如何实现InjectingClass?使用
RetentionPolicy.CLASS
?非常困难(但可行),因为这意味着您需要一个在编译时生成代码的注释处理器,然后
InjectingClass
几乎什么都不做。使用
.RUNTIME
几行(反射)代码。我是受ButterKnife库的启发。所以我只是想看看它是如何工作的?它正在编译代码,希望如此。它是如何工作的?.RetentionPolicy.RUNTIME我已经用过了。它会影响android的性能吗?编译时注入也会导致性能开销吗?编译时生成的工作在你之前就开始了将应用程序上传至手机。Butterknife是开源的,所以请看:)当这项工作在运行时发生时,它会稍微减慢速度。但通常情况下,数量不明显。