看过再也不会忘的Java 元注解 | 8月更文挑战

1. 分类

1.1 @Target

定义:标明注解在哪里使用。

其中 ElementType 有很多类型可以供我们使用,关于它的值和说明可以看下图:

使用:

@Target(ElementType.TYPE)
public @interface MyBindView {
}
复制代码

1.2 @Rentention

定义:标识这个注解怎么保存,是保存在源码中,还是编译期,还是运行期。

其中 RetentionPolicy 有3种类型,分别如下:

我们日常经常看到大的开源框架,说是编译期注解,就是 : RetentionPolicy.CLASS.使用方式就像上述那样使用就好了。

我们还是以一个实际的例子来看一下,我们声明三个注解,分别设置为 CLASS ,RUNTIME,SOURCE,然后作用于一个类中的不同方法,观察编译之后的变化:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface SourceAnnotation {
}

复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ClassAnnotation {
}
复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface SourceAnnotation {
}
复制代码
public class MeActivity extends AppCompatActivity {

    TextView tv;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_me);

        tv = findViewById(R.id.tv);
    }

    @SourceAnnotation
    public void testSourceAnnotation(){}

    @ClassAnnotation
    public void testClassAnnotation(){}

    @RuntimeAnnotation
    public void testRuntimeAnnotation(){}


}
复制代码

经过 Android Studio 编译运行一下,或者使用命令编译应该也可以,然后我们看一下 MeActivity.class 文件,这个文件在我们的 build\intermediates\javac\debug\compileDebugJavaWithJavac\classes\com.xxx(我们的包名)目录下。

MeActivity.class

public class MeActivity extends AppCompatActivity {
    TextView tv;

    public MeActivity() {
    }

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(layout.activity_me);
        this.tv = (TextView)this.findViewById(id.tv);
    }

    public void testSourceAnnotation() {
    }

    @ClassAnnotation
    public void testClassAnnotation() {
    }

    @RuntimeAnnotation
    public void testRuntimeAnnotation() {
    }
}
复制代码

可以看到 testSourceAnnotation 方法上已经没有了 @SourceAnnotation 注解了,.class 是编译后的结果,所以会保留 @ClassAnnotation 和 @RuntimeAnnotation.

1.3 @Documented

定义:相对于上面两个,这个可能就用的少一些了,它是一个标记注解。在使用 javac 工具为类生成帮助文档时是否保留其注解信息。

使用如下:

@Documented
public @interface MyBindView {
}
复制代码

我们也是用一个实际例子来阐述:
创建一个注解,注解应用范围为字段上,并且使用 @Documented 注解标注,如下:

@Target(ElementType.TYPE)
@Documented
public @interface MyAnnotation {

    String value() default "这是Documented注解";
}
复制代码

并且在类中使用该注解:

@MyAnnotation
public class MeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_me);

    }
}
复制代码

我们利用 Android Studio 工具生成 doc 文档,点这里:

image.png

在弹出的对话框中,勾选我们要生成文档的类(这里我只生成MeActivity.java)以及输出路径即可。
控制台底下也可以看一些日志信息:

image.png

在输出路径中,可以看到生成的文档 html ,点击打开 index.html:

image.png

然后如果我们去掉 @Documented ,再来看一下生成的文档:

image.png

就没有我们那个声明的注解了。

1.4 @Inherited

定义:被它修饰的注解是可以被继承的,如果有一个类使用了该注解,有子类继承了,那么子类是可以使用该注解。
给一个例子看一下就是:

1.声明一个注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {

    String value() default "value";
}
复制代码

2.创建一个父类Person ,子类 Woman 类,然后让父类使用注解并给 value 赋值

@MyAnnotation("人")
public class Person {
}
复制代码
public class Woman extends Person{

    public String getValue(){

        Class<? extends Woman> womanClazz = getClass();
        MyAnnotation annotation = womanClazz.getAnnotation(MyAnnotation.class);
        return annotation.value();
    }

}
复制代码
public class TestAnn {

    public static void main(String[] args){

        Woman woman = new Woman();
        System.out.println(woman.getValue());
    }
}
复制代码

控制台打印:

image.png

woman 没有定义注解,也可以获取到父类设置的注解值。

好了,今天分享就到这了,有问题评论区见哦~?

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享