一. 什么是注解(Annotation)
Java注解是什么,以下是引用自维基百科的内容
Java注解又称Java标注,是JDK5.0版本开始支持加入源代码的特殊语法元数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容。当然它也支持自定义Java标注。
二. 如何定义一个注解
比如定义一个名字叫 info
的注解,如下 新建一个文件 info.java
,代码如下:
package com.demo;
//定义了一个叫做 info 的注解
public @interface info {
}
有的注解存在于源文件期,有的标签存在于编译期,有的标签存在于运行期
@Target(ElementType.FIELD) //注解作用在类的字段上
@Retention(RetentionPolicy.RUNTIME) //注解存在于运行期
public @interface info {
}
@Target, @Retention 是元注解,咋又出来一个元注解,可以望文生义:元就是元始的意思,用来注释注解的注解。
Target 元注解
用处:用来定义注解的用在的地方,比如是用在类上啊,还是用在字段上啊,还是用在方法上啊等。我们列出几个常用的就行,其它的自行下去查义即可,如下:
ElementType.TYPE 应用于类的元素
ElementType.METHOD 应用于方法级
ElementType.FIELD 应用于字段或属性(成员变量)
ElementType.ANNOTATION_TYPE 应用于注释类型
ElementType.CONSTRUCTOR 应用于构造函数
ElementType.LOCAL_VARIABLE 应用于局部变量
ElementType.PACKAGE 应用于包声明
ElementType.PARAMETER 应用于方法的参数
Retention 元注解
用处:用来定义注解的生命周期(或叫保留策略,我更喜欢叫生命周期) 取值:
SOURCE 在源文件中有效(即源文件保留)
CLASS 在class文件中有效(即class保留)
RUNTIME 在运行时有效(即运行时保留)
举例如
@GetMapping注解,用于SpringMVC上接受用户响应,查询数据库表的方法,具体方法如下:@RequestMapping("/findAll") public List<User> findAll(){ return userService.findAll(); }
调出它的源码如下:
@Target({ElementType.METHOD}) //表示定义在方法上 @Retention(RetentionPolicy.RUNTIME)//生命周期运行时有效 @Documented @RequestMapping( method = {RequestMethod.GET} ) public @interface GetMapping { @AliasFor( annotation = RequestMapping.class ) String name() default ""; @AliasFor( annotation = RequestMapping.class ) String[] value() default {}; @AliasFor( annotation = RequestMapping.class ) String[] path() default {}; @AliasFor( annotation = RequestMapping.class ) String[] params() default {}; @AliasFor( annotation = RequestMapping.class ) String[] headers() default {}; @AliasFor( annotation = RequestMapping.class ) String[] consumes() default {}; @AliasFor( annotation = RequestMapping.class ) String[] produces() default {}; }
通过上面的叙述,我们小小总结一下
- 注解就是类似标签一样的东西
- 注解定义是用
public @interface 注解名 { }
- 注解是有使用的地方和生命周期的
- 注解能用在类上,字段上,方法上,参数上等
三 如何使用注解
我们来扩展一下上面的 info
注解,代码如下:
@Target(ElementType.FIELD) //注解作用在类的字段上
@Retention(RetentionPolicy.RUNTIME) //注解存在于运行期
public @interface info {
String job(); //job属性
String comment(); //comment属性
}
对的,你又看到了注解还能定义属性,记住,就按照上面的定义就行了。 主要看怎么用
我们定义一个工人类Worker
,如下:
//工人类
public class Worker {
//工人的名字
public String name;
//工人简介方法,打印工作的基本信息
public void show(){
}
}
很简单的一个类,我们在 name 字段上添加我们定义的info
注解,如下
public class Worker {
//注解是能给属性传值的,job和comment和info定义中的相呼应,对,属性就是这样用的
@info(job = "工程师",comment = "工作很努力")
public String name;
public void show(){
}
}
上面我们给 name 字段添加了我们自己定义的注解,并且给注解中传了工作的职位是:工程师 ,评价是:工作很努力 我们想在show()方法中,打印出工作的名字,职位,和评价
获取注解中的 job和 comment可以通过反射获取 ,注意看注释,如下
public class Worker {
//注解是能给属性传的,job和comment和定义中的相呼应
@info(job = "工程师",comment = "工作很努力")
public String name;
public void show(){
//1 获取本类的字节码
Class clz = this.getClass();
//2 获取类中定义的字段
Field[] fields = clz.getDeclaredFields();
//3 遍历字段,看看哪个字段有info注解
for (Field field : fields){
//4 判断此字段上是否有 info 注解
info annotation = field.getAnnotation(info.class);
//5 如果不为 null ,说明 field上有info注解
if (annotation != null){
//6 通过info注解,获取info注解中的 job和comment
String job = annotation.job();
String comment = annotation.comment();
//7 打印出来
System.out.println("我是:" + this.name + " 我的职位是:" + job + " 我的评价是:" + comment);
}
}
}
通过上面可以看出,使用注解步骤如下:
- 获取类的 Class ,也就是类的字节码
- 获取类的所有字段的字码码数组
- 遍历字段
- 通过
info annotation = field.getAnnotation(info.class)
获取字段上对应的注解 - 通过注解,获取注解中传的值
我们再来写一个 main 函数,调用上面那段代码:如下
public class Demo1 {
public static void main(String[] args){
Worker worker = new Worker();
worker.name = "待兔,www.helloworld.net 站长";
worker.show();
}
}