自定义注解
如果要自定义一个注解,首先要明白注解怎样定义,也就是注解定义时的格式。
先来看一个Spring框架的注解@Component。
可以看到,定义注解有两个关键点:元注解、方法(在注解中又叫属性)。
注解的属性(接口中的方法)
一直都在强调,注解的本质是接口,所以,它的内部可以声明方法,在注解中,这些方法又叫做属性。
public @interface TestAnnotation {
String value();
}
声明这个方法(属性)又有什么用?为了探究它有什么用,先使用一下这个注解。
报错的原因是没有给value这个属性赋值,所以要给它赋值
再次返回到注解的定义中,看到value方法的返回值类型是String。在使用时(赋值时),要与方法返回值的类型一致。
如果注解只有一个属性,并且这个属性的名称是value,则在使用时,可以在括号中直接写值。
也就是说,对于上面的例子,可以这样使用
@Target("hello") //等价于@Target(value = "hello")
除此之外,还可以设置方法返回默认值,也就是这个属性的默认值。
public @interface TestAnnotation {
String value() default "hello";
}
在方法声明后跟上default关键字,在default关键字后加上默认的返回值(或者说是默认的属性值)。
如果一个属性有了默认值,如果不显示给这个默认值赋值,就会使用默认值,而不会像上面那样报错。
返回值类型(属性类型)的限制:在注解中,返回值的类型只能是:简单类型、String、枚举类型、注解以及它们的数组
关于怎样读取这些值,在后面的注解解析中学习,现在只需要知道怎么定义,怎么使用即可
元注解
元注解,本身也是注解,它用来注解定义是说明注解。Java提供了4种预定义的元注解。
@Target
@target用来说明注解修饰代码的哪个部分。(也就是注解可以出现的位置,例如:@Overide是用来修饰方法的。通过这个元注解,指定注解可以修饰类、字段、方法)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
自己标记自己?(此处禁止套娃)这里表示@Target这个注解作用的类型时ANNOTATION_TYPE,也就是作用于注解
这是Target注解的部分定义,@Taget只有一个属性value,它的类型是ElementType的一个数组。根据之前的分析,value的类型只能是简单类型、String、枚举和注解。
在使用时,从@Target(ElementType.ANNOTATION_TYPE)可以推断,它是一个枚举类型。
通过追溯,可以看到它的确是一个枚举类型。通过枚举,限定了value属性的取值。
注解中声明value是一个数组,在使用的时候为什么直接使用了一个值?
通常,对于一个数组赋值,因该使用大括号:
@Target({ElementType.ANNOTATION_TYPE})
如果大括号中只有一个值,可以省略大括号
@Target最常用的value属性值:
1. ElementType.TYPE:说明注解作用于类(或接口)。
2. ElementType.METHOD:说明注解作用于方法。
3. ElementType.FIELD:说明注解作用于字段。
@Retention
@Retention用来说明注解保存的位置(或时间长短)。注解可以仅保存在源代码中,供编译器识别(例如Override);注解可以保存在字节码文件中(即已经被编译),运行时,JVM不需要读取(加载);注解在运行是被JVM读取,可以通过反射进行使用。(关于如何使用,放到后面的注解解析部分)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
这个注解的属性是一个枚举类型RententionPolicy,他总共有三个值SOURCE,CLASS和RUNTIME。对应于上面说到的源码、字节码、运行时。
@Document
@Document,用来说明注解是否会出现在文档中。当使用javadoc工具生成文档时,如果只有被@Document修饰的注解,才会出现在文档中。
@Inherited
@Inherited,如果一个注解被@Inherited修饰,当这个注解作用于一个类/接口,那么这个类的子类都会自动的被这个注解修饰。
目前为止,至少可以读懂一个注解(有哪些属性,作于在什么地方),可以自定义一个有属性的注解
推荐阅读
-
asp.net web页面自定义分页控件使用详解
-
React Native使用Modal自定义分享界面的示例代码
-
php读写excel类,支持多工作簿和自定义样式,读写excel_PHP教程
-
用javascript实现自定义标签_javascript技巧
-
php生成随机密码的自定义函数(转载分享),php自定义
-
thinkphp autoload 命名空间自定义 namespace,thinkphpautoload
-
在React中使用Native如何实现自定义下拉刷新上拉加载的列表
-
Android 入门第十讲02-广播(广播概述,使用方法(系统广播,自定义广播,两个activity之间的交互和传值),EventBus使用方法,数据传递,线程切换,Android的系统广播大全)
-
详解PyCharm 自定义文件和代码模板实例
-
Spring的注解简单介绍