一. 什么是注解(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);
            }
        }
    }

 

通过上面可以看出,使用注解步骤如下:

  1. 获取类的 Class ,也就是类的字节码
  2. 获取类的所有字段的字码码数组
  3. 遍历字段
  4. 通过 info annotation = field.getAnnotation(info.class) 获取字段上对应的注解
  5. 通过注解,获取注解中传的值

 

我们再来写一个 main 函数,调用上面那段代码:如下

public class Demo1 {
    public static void main(String[] args){
        Worker worker = new Worker();
        worker.name = "待兔,www.helloworld.net 站长";
        worker.show();
    }
}