• Java自定义注解使用


    最近上子路老师的spring源码课,发现部分刚入门的新同学对自定义注解这一块知识不太了解,于是写下这篇文章,希望能够解决一些同学心中的疑问

    回到正文,什么是注解?

    注解和class,Interface一样,是Java的一种数据类型。注解是不会直接对程序有说明影响的,你可以把它简单的理解为一种标记

    怎么自定义一个注解?

    自定义注解语句和定义类是一样的,只是声明关键字变成了@interface,如哦public @interface Feiyang

    1 package com.feiyang.test;
    2 
    3 public class AnnotationTest {
    4 
    5 }
    View Code

    定义一个注解之后我们就可以使用它了,定义一个类来添加自定义注解

     1 package com.feiyang.model;
     2 
     3 import com.feiyang.annotation.FeiyangAnnotation;
     4 
     5 @FeiyangAnnotation
     6 public class Feiyang {
     7 
     8     @FeiyangAnnotation
     9     private String name;
    10 
    11     @FeiyangAnnotation
    12     public Feiyang(String name) {
    13         this.name = name;
    14     }
    15 
    16     public String getName() {
    17         return name;
    18     }
    19 
    20     public void setName(String name) {
    21         this.name = name;
    22     }
    23 
    24 }
    View Code

    我们可以看到类、属性、方法和构造方法上都加上了我们定义的注解,并且程序并未报错

    但是我们发现有些注解是只能在特定的地方才能使用,否则就会报错的,比如spring提供的@Component等注解只能用在类上,用在方法等其他地方是会报错的

    这是因为Java为我们提供了一些源注解,可以用来定义注解的一些性质,比如@Target

     1 package com.feiyang.annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Target;
     5 
     6 /**
     7  * Target注解是java提供的一种源注解,可以用来定义注解的作用域
     8  * 使用Target需要提供ElementType枚举类的值,值可以是一个也可以是多个组成的一个数组
     9  * ElementType.TYPE 定义注解可以作用在类、接口等声明上
    10  * ElementType.FIELD 定义注解可以作用在属性上
    11  * ElementType.METHOD 定义注解可以作用在方法上
    12  * ElementType.PARAMETER 定义注解可以作用在方法参数上
    13  * ElementType.CONSTRUCTOR 定义注解可以作用在构造方法上
    14  * ElementType.LOCAL_VARIABLE 定义注解可以作用在局部变量上
    15  * ElementType.ANNOTATION_TYPE 定义注解可以作用在注解上
    16  * ElementType.PACKAGE 定义注解可以作用在包声明上
    17  * ElementType.TYPE_PARAMETER jdk1.8之后添加的,笔者也不知道
    18  * ElementType.TYPE_USE 同上
    19  * 如果不加@Target注解,那该注解就能作用在任意地方
    20  */
    21 @Target({ElementType.FIELD, ElementType.METHOD})
    22 public @interface FeiyangAnnotation {
    23 
    24 }
    View Code

    添加@Target限制之后就会发现原来注解在类上和构造方法上的注解编译报错,提示FeiyangAnnotation注解不能作用在这里

    我们知道有些注解中是存在一些属性(例如Target)的,我们也可以给我们自定义的注解添加属性

     1 package com.feiyang.annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Target;
     5 
     6 /**
     7  * Target注解是java提供的一种源注解,可以用来定义注解的作用域
     8  * 使用Target需要提供ElementType枚举类的值,值可以是一个也可以是多个组成的一个数组
     9  * ElementType.TYPE 定义注解可以作用在类、接口等声明上
    10  * ElementType.FIELD 定义注解可以作用在属性上
    11  * ElementType.METHOD 定义注解可以作用在方法上
    12  * ElementType.PARAMETER 定义注解可以作用在方法参数上
    13  * ElementType.CONSTRUCTOR 定义注解可以作用在构造方法上
    14  * ElementType.LOCAL_VARIABLE 定义注解可以作用在局部变量上
    15  * ElementType.ANNOTATION_TYPE 定义注解可以作用在注解上
    16  * ElementType.PACKAGE 定义注解可以作用在包声明上
    17  * ElementType.TYPE_PARAMETER jdk1.8之后添加的,笔者也不知道
    18  * ElementType.TYPE_USE 同上
    19  * 如果不加@Target注解,那该注解就能作用在任意地方
    20  */
    21 @Target({ElementType.FIELD, ElementType.METHOD})
    22 public @interface FeiyangAnnotation {
    23 
    24     /**
    25      * 我们可以在注解当中添加方法,这样就能丰富我们注解的功能了
    26      * 方法名称就是使用该注解时的属性,返回值类型就是使用是时的属性值的类型,返回值就是使用时的属性值
    27      * 例如在某个属性上使用该注解时@FeiyangAnnonation(value = "value属性值", name = "name属性值")
    28      * 由于我们定义了一个方法名叫value,使用时就需要提供一个value属性
    29      * 我们定义的返回值类型为Stirng,value属性的类型就要是String类型
    30      * value属性的值是我们解析该注解的时候用到的
    31      *
    32      * @return
    33      */
    34     public String value();
    35 
    36     /**
    37      * 上面定义的方法在使用时是一定要提供value属性及其属性值的
    38      * 如果想在使用时不用填写属性,可以给方法加一个默认值(default)
    39      *
    40      * @return
    41      */
    42     public String name() default "";
    43 
    44 }
    View Code

    由于value方法没有默认值,如果不为注解提供value属性值就会报错,这里我们为注解添加属性值

     

    有个小知识点,如果注解里面有个方法名称为value,并且使用时你只提供value属性,这时候是不需要写属性名的,可以直接写属性值

    如果注解中没有value方法或者需要提供多个属性时,则必须填写"属性 = 属性值"

    例如@FeiyangAnnotation("feiyang field value")等于@FeiyangAnnotation(value = "feiyang field value")

    而@FeiyangAnnotation(value = "feiyang method value", name = "feiyang method name")不能简写成@FeiyangAnnotation("feiyang method value", name = "feiyang method name")

    前面说过,注解是不能直接影响程序的,就像人名一样,我叫肥羊,你也可以叫肥羊,大家都可以叫肥羊,肥羊本身没有任何意义只是一个代号,一种表示

    但是我们可以通过解析这种标识去赋予它特殊的意义,就像子路老师通过为大家授业解惑,使子路这个名字有了特殊意义,大家一听到子路老师的名字就浮现出大神、帅气、车快,人快、3秒等词

    话不多说,上代码

     1 package com.feiyang.test;
     2 
     3 import com.feiyang.annotation.FeiyangAnnotation;
     4 import com.feiyang.model.Feiyang;
     5 
     6 import java.lang.reflect.Field;
     7 
     8 public class AnnotationTest {
     9 
    10     public static void main(String[] args) {
    11         // 解析注解分为以下几个步骤
    12         // 1、获取Class对象
    13         // 获取对象可以通过类.class获取,也可以通过对象.getClass方法获取,视具体情况而定
    14         Class<Feiyang> clazz = Feiyang.class;
    15         // 2、获取注解作用的地方,如属性,方法等。如果注解就是作用在类中,可以跳过这一步
    16         // FeiyangAnnotation只能加在属性或者方法上,以属性为例,获取类中所有属性,遍历执行第三步
    17         Field[] fields = clazz.getDeclaredFields();
    18         for (Field field : fields) {
    19             // 3、判断目标是否添加了该注解
    20             if (field.isAnnotationPresent(FeiyangAnnotation.class)) {
    21                 // 如果添加了注解,我们就可以操作添加了注解的元素或者解析注解了
    22                 // spring的@Autowired注解就是这个原理,当解析到类中的某个属性添加了@Autowired注解时
    23                 // spring就会获取这个属性的类型,然后去容器中找对应的bean,如果找到了就注入给这个属性
    24 
    25                 // 4、获取注解对象,解析属性
    26                 // 添加注解的话我们就可以获取到这个注解对象了
    27                 FeiyangAnnotation annotation = field.getAnnotation(FeiyangAnnotation.class);
    28                 // 获取到这个注解对象之后我们就可以拿到这个注解的属性值了
    29                 // 前面我们使用该注解提供的属性值就相当于注解方法的返回值
    30                 // 如果我们方法有默认值而我们又没有提供对应的属性,我们调用方法获取到的就是默认值
    31                 String value = annotation.value();
    32                 String name = annotation.name();
    33                 // 获取到属性值之后我们就可以通过判断属性值确认逻辑了,这里笔者就不演示逻辑了,笔者把属性值打印一下给大家看一下
    34                 System.out.println(value + "
    " + name);
    35             }
    36         }
    37     }
    38 
    39 }
    View Code

    运行代码可以看到控制台并没有打印任何信息

     这是什么情况?难道笔者前面说的都是错的吗?不要着急,这其实是注解缺少了一个值的原因

    我们前面说过Target源注解,Java还提供了另外一个源注解@Retention标记注解存在的时间,我们需要添加这个源注解才能使代码达到我们的预期

     通过上面的注释我们可以发现是没有加@Retention注解的原因导致执行时注解就被丢弃了,现在我们加上这个注解并定义为RUNTIME,再次执行程序,可以看到打印出了我们想要的结果

     剩下的对方法上的注解的解析大家可以自己去试一下

  • 相关阅读:
    删除字符串组中相同元素,并删除值为空的元素 (转载,笔记)
    获取操作系统语言
    .net 传递中文参数解决办法
    古怪问题:vs2003程序 在繁体平台下控件位置发生变化
    Godaddy邮箱C#发送邮件设置
    无法显示隐藏文件的解决方法
    虚拟机文件
    sql 2000 修复问题
    看QQ是否在线
    sql 知识摘录
  • 原文地址:https://www.cnblogs.com/big-feiyang/p/11661442.html
Copyright © 2020-2023  润新知