• Java 写个注解并使用


    注解

    概念

    注解(Annotation),也叫元数据,是一种代码级别的说明。是Java 的JDK1.5版本开始引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、属性、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

    作用

    1. 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】

    2. 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】

    3. 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

    4. 很多框架技术的新版本中,都可以使用注解替代XML配置文件;【SpringBoot】

    写个注解

    光用没意思,下面学一下怎么写注解

    注解的声明

    首先是要声明一个注解,注解的声明形式如下:

    public @interface  注解名字 {
    	注解属性
    }
    
    • 1
    • 2
    • 3

    例如我们声明注解类型MyAnnotation.java,如下所示:

    public @interface MyAnnotation {
    }
    
    • 1
    • 2

    非常简单,然后就能用了:

    image-20220807153957682

    当然这不算完,下面看一下编写注解注意点,首先是我们可以设置注解的修饰目标

    注解修饰目标

    注解可以用于不同的目标,例如接口、类、构造方法、方法、属性、类型等;

    声明注解时,可以使用JDK中已经定义的注解@Target声明注解修饰的目标;

    @Target中使用枚举ElementType表示修饰目标,有如下几种修饰目标:

    方法方法描述
    ANNOTATION_TYPE表示该注解能用于注解类型;
    CONSTRUCTOR表示该注解能用于构造方法;
    FIELD表示该注解能用于域;
    LOCAL_VARIABLE表示该注解能用于局部变量;
    METHOD表示该注解能用于方法:
    PACKAGE表示该注解能用于包;
    PARAMETER表示该注解能用于方法参数;
    TYPE表示该注解能用于类、接口、枚举声明;

    例如MyAnnotation2,为其添加@Target,指定修饰目标为TYPE,即类、接口、枚 举等声明可用;

    @Target(value=ElementType.TYPE)
    public @interface MyAnnotation2 {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    测试一下,可以发现不能放在方法上

    image-20220807154646064

    注意:

    @Target()有一个value属性名称,属性值是数组,每一元素是ElementType类型
    @Target使用的时候 用小括号,括号内部value= {},{}表示数组,每个元素用逗号隔开
    
    • 1
    • 2

    解决这个的方式是在ElementType中再加一项,让他可以加在方法上

    @Target(value = {ElementType.TYPE,ElementType.METHOD})
    public @interface MyAnnotation2 {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    这样就没问题了

    image-20220807154753745

    注解生命周期

    JDK中已经定义了注解@Retention,用来定义注解的声明周期;

    使用枚举RetentionPolicy定义生命周期,共有三种情况

    方法方法描述
    SOURCE示该注解只在源代码级别保留,编译时就会被忽略:
    CLASS示该洼解编译时被保留,在class文件中存在,但VM将会忽略:
    RUNTIME示该注解被VM保留,所以能在运行时被VM或其他使用反射机制的代码所读取和使用,

    例如编写MyAnnotation3,指定其生命周期为RUNTIME

    @Target(value=ElementType.TYPE)
    @Retention(value=RetentionPolicy.RUNTIME)
    public @interface MyAnnotation3 {
    }
    
    • 1
    • 2
    • 3
    • 4

    使用以下@MyAnnotation3

    image-20220807161429609

    我们查看编译后的class文件,就找不到@MyAnnotation3了

    image-20220807161354886

    注解属性

    之前说声明的时候就提到过注解属性,例如注解的声明形式如下:

    public @interface  注解名字 {
    	注解属性
    }
    
    • 1
    • 2
    • 3

    注解属性就写在里面,注解属性看起来像个方法,其实是属性,属性类型包括所有基本类型、 String、Class、enum、 Annotation、以上类型的数组形式,注解元素声明形式如下:

    public String urlpattern();
    public boolean onload();
    
    • 1
    • 2

    编写MyAnnotation4.java,添加2个属性,如下所示:

    @Target(value=ElementType.TYPE)
    @Retention(value=RetentionPolicy.RUNTIME)
    public @interface MyAnnotation4 {
        public String urlpattern();
        public boolean onload();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注解中的属性在使用的时候可以指定值,也可以在声明的时候赋默认值;

    编写MyAnnotation5,对onload属性赋默认值为false;

    @Target(value=ElementType.TYPE)
    @Retention(value=RetentionPolicy.RUNTIME)
    public @interface MyAnnotation5 {
        public String urlpattern() ;
        public boolean onload() default false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注解的使用

    使用注解非常简单,不管是JDK中内置的已经定义好的注解还是自定义的注解,只要使用 @注解名称(属性值列表)的形式,均可以使用;

    例如我们编写 LoginWebComponent中使用上面定义的 MyAnnotaion5,指定了urlpattern及onload属性值:

    //onload这个属性可以不给值 因为是默认的false
    @MyAnnotation5(urlPattern = "/user/login", onload = false)
    public class LoginWebComponent {
        public void doPost(String urlPattern, boolean onload) {
            System.out.println("请求的urlPattern=" + urlPattern + ",οnlοad=" + onload);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    那我们怎么对注解进行操作呢?比如说获取urlPattern的值到doPost里,直接上面这样写肯定是不行的。

    我们需要通过反射来对注解进行应用

    比如说获取注解中的属性:

    //获取LoginWebComponent的Class对象
    Class<?> loginClazz = Class.forName("com.shixun.annotation.LoginWebComponent");
    //获取LoginWebComponent类上使用的注解注解对象
    MyAnnotation5 annotation5 = loginClazz.getAnnotation(MyAnnotation5.class);
    //获取注解的属性值
    String urlPattern = annotation5.urlPattern();
    boolean onload = annotation5.onload();
    // 打印获取到的注解属性
    System.out.println("打印获取到的注解属性================");
    System.out.println("urlPattern:"+urlPattern+" | onload:"+onload);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    image-20220807162841273

    也可以用其他方法:

    比如再使用获得到的注解属性动态创建LoginWebComponent对象,调用doPost方法

    //动态创建LoginWebComponent对象
    Object loginInstance = loginClazz.newInstance();
    //动态获取LoginWebComponent的doPost方法
    Method doPostMethod = loginClazz.getDeclaredMethod("doPost", String.class, boolean.class);
    //调用doPost方法
    Object result = doPostMethod.invoke(loginInstance, urlPattern, onload);
    System.out.println(result);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再比如获取LoginWebComponent类上所有的注解

     System.out.println("获取LoginWebComponent类上所有的注解===========================");
     Annotation[] annotations = loginClazz.getAnnotations();
     for (Annotation annotation : annotations) {
         System.out.println(annotation.toString());
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20220807163437855

  • 相关阅读:
    人脸106和240点位检测解决方案
    2024最新互联网大厂面试题,(java,python,vue)
    Zookeeper高级特性与API
    身临其境之谁是猎人
    C++多态的理解
    vue项目 的创建
    互融云软件系统提供商|一款成熟的数字资产交易系统
    Git 修改已提交的用户名和邮箱
    【电源专题】案例:芯片规格书使能定义高电平最小阈值1.4V,那真的是到1.4V时才开始输出?
    【Java SE]位运算和移位运算注意事项
  • 原文地址:https://blog.csdn.net/weixin_45525272/article/details/126213175