Java注解使用总结

作者: 鱼鱼鱼三条鱼ii | 来源:发表于2019-06-25 10:32 被阅读11次

    Java注解总结

    注解(Annotation)在JDK1.5之后增加的一个新特性,注解的引入意义很大,有很多非常有名的框架,比如Hibernate、Spring等框架中都大量使用注解。注解作为程序的元数据嵌入到程序。注解可以被解析工具或编译工具解析。
    注解属于 Java中的一种类型,同 类class 和 接口interface 一样。

    一、元数据

    要想理解注解(Annotation)的作用,就要先理解Java中元数据的概念。

    1. 元数据概念

    元数据是关于数据的数据。在编程语言上下文中,元数据是添加到程序元素如方法、字段、类和包上的额外信息。对数据进行说明描述的数据。

    2.元数据的作用

    一般来说,元数据可以用于创建文档(根据程序元素上的注释创建文档),跟踪代码中的依赖性(可声明方法是重载,依赖父类的方法),执行编译时检查(可声明是否编译期检测),代码分析。
    如下:
    1) 编写文档:通过代码里标识的元数据生成文档  
    2)代码分析:通过代码里标识的元数据对代码进行分析  
    3)编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查

    3.Java平台元数据

    注解Annotation就是java平台的元数据,是 J2SE5.0新增加的功能,该机制允许在Java 代码中添加自定义注释,并允许通过反射(reflection),以编程方式访问元数据注释。通过提供为程序元素(类、方法等)附加额外数据的标准方法,元数据功能具有简化和改进许多应用程序开发领域的潜在能力,其中包括配置管理、框架实现和代码生成。

    二、注解

    注解的类型一般包括:元注解 、 Java内置注解 & 自定义注解三种,下面我将解释这三种注解使用方法。

    2.1元注解

    JDK除了在java.lang提供了上述内建注解外,还在java.lang。annotation包下提供了6个Meta Annotation(元Annotation),其中有5个元Annotation都用于修饰其他的Annotation定义。其中@Repeatable专门用户定义Java 8 新增的可重复注解。
    @Documented

    @Documented用户指定被该元Annotation修饰的Annotation类将会被javadoc工具提取成文档,如果定义Annotation类时使用了@Documented修饰,则所有使用该Annotation修饰的程序元素的API文档中将会包含该Annotation说明。
    @Inherited

    @Inherited指定被它修饰的Annotation将具有继承性——如果某个类使用了@Xxx注解(定义该Annotation时使用了@Inherited修饰)修饰,则其子类将自动被@Xxx修饰。
    @Retention

    @Retention:表示该注解类型的注解保留的时长。当注解类型声明中没有@Retention元注解,则默认保留策略为RetentionPolicy.CLASS。关于保留策略(RetentionPolicy)是枚举类型,共定义3种保留策略,如下表:
    @Target

    @Target:表示该注解类型的所适用的程序元素类型。当注解类型声明中没有@Target元注解,则默认为可适用所有的程序元素。如果存在指定的@Target元注解,则编译器强制实施相应的使用限制。
    @Repeatable

    定义:可重复注解

    2.2Java内置注解

    Java提供了多种内建的注解,下面接下几个比较常用的注解:@Override、@Deprecated、@SuppressWarnings以及@FunctionalInterface这4个注解。内建注解主要实现了元数据的第二个作用:编译检查。

    @Override
    用途:用于告知编译器,我们需要覆写超类的当前方法。如果某个方法带有该注解但并没有覆写超类相应的方法,则编译器会生成一条错误信息。如果父类没有这个要覆写的方法,则编译器也会生成一条错误信息。

    @Override可适用元素为方法,仅仅保留在java源文件中。

    @Deprecated
    用途:使用这个注解,用于告知编译器,某一程序元素(比如方法,成员变量)不建议使用了(即过时了)。
    @SuppressWarnings
    用途:用于告知编译器忽略特定的警告信息,例在泛型中使用原生数据类型,编译器会发出警告,当使用该注解后,则不会发出警告。

    注解类型分析: @SuppressWarnings可适合用于除注解类型声明和包名之外的所有元素,仅仅保留在java源文件中。
    @FunctionalInterface
    用途:用户告知编译器,检查这个接口,保证该接口是函数式接口,即只能包含一个抽象方法,否则就会编译出错。

    2.3自定义注解
    1. 注解的定义
    // 通过 @interface 关键字进行定义
    // 形式类似于接口,区别在于多了一个 @ 符号
    
    public @interface Test_Annotation {
    
    }
    
    1. 注解的属性
    <-- 1. 定义 注解的属性 -->
    // 注解的属性 在定义该注解本身时 进行定义
    public @interface Test_Annotation {
    // 注解的属性 = 成员变量
    // 注解只有成员变量,没有方法
    
        // 注解@Test_Annotation中有2个属性:id 和 msg  
        int id();
        String msg() default "Hello" ;
    
        // 说明:
          // 注解的属性以 “无形参的方法” 形式来声明
          // 方法名 = 属性名
          // 方法返回值 = 属性类型 = 8 种基本数据类型 + 类、接口、注解及对应数组类型
          // 用 default 关键值指定 属性的默认值,如上面的msg的默认值 = ”Hi“
    }
    
    <-- 2. 赋值 注解的属性 -->
    // 注解的属性在使用时进行赋值
    // 注解属性的赋值方式 = 注解括号内以 “value=”xx” “ 形式;用 ”,“隔开多个属性
    
    // 注解Test_Annotation 作用于A类
    // 在作用 / 使用时对注解属性进行赋值
    @Test_Annotation(id=1,msg="hello")
    public class A {
      }
    
    // 特别说明:若注解只有一个属性,则赋值时”value“可以省略
    
    // 假设注解@Test_Annotation只有1个msg属性
    // 赋值时直接赋值即可
    @Test_Annotation("hello")
    public class A {
      }
    
    
    1. 注解的使用
    // 在类 / 成员变量 / 方法 定义前 加上 “@注解名” 就可以使用该注解
    @Test_Annotation
    public class Test {
    
        @Test_Annotation
        int a;
        
        @Test_Annotation
        public void print(){}
    
    }
    
    
    1. 获取注解
    <-- 步骤1:判断该类是否应用了某个注解 -->
    // 手段:采用 Class.isAnnotationPresent() 
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
    
    <-- 步骤2:获取 注解对象(Annotation)-->
      // 手段1:采用getAnnotation()  ;返回指定类型的注解
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
      // 手段2:采用getAnnotations() ;返回该元素上的所有注解
    public Annotation[] getAnnotations() {}
    

    三、实例

    1.定义注解

    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnnotation {
        int id();
        String msg() default "测试";
    }
    

    2.添加注解

    @TestAnnotation(id = 1, msg = "类注解")
    public class Test {
        @TestAnnotation(id = 2,msg = "变量注解")
        int a;
        @TestAnnotation(id = 3,msg = "方法注解")
        public void print(){
            System.out.println("方法打印");
        }
    }
    

    3.运行时使用注解

     public static void main(String[] args) {
            Test test = new Test();
            // 获取类的对象
            Class testClass = test.getClass();
            // 反射获取方法
            Method[] methods = testClass.getDeclaredMethods();
            for(Method m : methods){
                // 判断是否方法是否存在注解
                if(m.isAnnotationPresent(TestAnnotation.class)){
                    try {
                        // 获取方法和类的注解
                        TestAnnotation classAnnotation = Test.class.getAnnotation(TestAnnotation.class);
                        System.out.println("id = " + classAnnotation.id());
                        System.out.println("msg = " + classAnnotation.msg());
                        m.setAccessible(true);
                        m.invoke(test);
                        TestAnnotation methodAnnotation = m.getAnnotation(TestAnnotation.class);
                        System.out.println("id = " + methodAnnotation.id());
                        System.out.println("msg = " + methodAnnotation.msg());
                    }catch (InvocationTargetException e){
                        e.printStackTrace();
                    }catch (IllegalAccessException e){
                        e.printStackTrace();
                    }
    
                }
            }
    // 输出结果
    id = 1
    msg = 类注解
    方法打印
    id = 3
    msg = 方法注解
    

    相关文章

      网友评论

        本文标题:Java注解使用总结

        本文链接:https://www.haomeiwen.com/subject/rrzzqctx.html