首页 > 编程语言 > 详细

Java 注解

时间:2020-01-15 22:11:48      阅读:69      评论:0      收藏:0      [点我收藏+]

一.什么是注解

? 注解,可以理解为标签,是一种特殊的“注释”,用来标识或解释Java代码,是给机器看的(而注释是给程序员看的)。

? 注解的定义:注解也叫元数据,跟类、接口、枚举是同一个层次的,也是java的一种类型,在Java SE 5.0开始引入,放在Java源码的类、方法、字段、参数前面,用来进行注释或说明。

二.注解的作用

注解的作用有以下三类:

  • 编写文档:通过代码里标识的注解生成文档(生成文档doc文档)
  • 代码分析:通过代码里标识的注解对代码进行分析(使用反射)
  • 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查(Override等)

三.注解的分类

  • 标准注解

    标准注解是指JDK自带的几个注解,主要有这几个:

    • @Override:检测该注解标注的方法是否是继承自父类(接口)的
    • @Deprecated:该注解标注的内容,标识已过时
    • @SuppressWarnings:压制警告,一般传递参数all,@SuppressWarnings
    • @FunctionalInterface:函数式接口注解
  • 元注解

    元注解是用来修饰其他注解的,主要有以下几种:

    • @Retention:解释说明了注解的生命周期,有以下三种取值

      • RetentionPolicy.SOURCE:注解只在源码阶段保留,在编译器进行编译时将注解丢弃或忽视
      • RetentionPolicy.CLASS:注解只保留到编译进行时,不会被加载进JVM
      • RetentionPolicy.RUNTIME:注解保留到程序运行时,会被加载进入JVM中,所以在程序运行时可以获取到它们
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MyAnnotation {
          int value();
      }

      如果定义注解时@Retention不存在,则该Retention默认为RetentionPolicy.CLASS,但我们通常自定义的注解都是RUNTIME时使用,所以必须要加上@Retention(RetentionPolicy.RUNTIME

    • @Documented:用来将注解中的元素包含到Javadoc文档中

    • @Target:定义注解所修饰的对象范围,有以下7种取值

      • ElementType.PACKAE:可以给一个包进行注解
      • ElementType.TYPE:可以给一个类型进行注解,比如类,接口,枚举等
      • ElementType.CONSTRUCTOR:可以给构造方法进行注解
      • ElementType.METHOD:可以给方法进行注解
      • ElementType.PARAMETER:可以给一个方法内的参数进行注解
      • ElementType.FIELD:可以给属性进行注解
      • ElementType.LOCAL_VARIABLE:可以给局部变量进行注解
      @Target(ElementType.METHOD) // 限制了注解MyAnnotation只能用于解释说明某个方法
      public @interface MyAnnotation {
          int value();
      }
    • @Inherited:定义子类是否可以继承父类定义的注解,如果一个class使用了@Inherited修饰的注解,那么这个注解将被用于这个class的子类。

      1. 这个元注解只对类的继承起效,对接口的继承无效。
      2. 适用前提是:子类没有被任何注解应用。
      // 元注解@Inherited 作用于 注解MyAnnotation
      @Inherited
      public @interface MyAnnotation {
          int value();
      }
      // 注解MyAnnotation作用于 class A
      @MyAnnotation
      public class A {
      
      }
      // class B 继承了 class A,而且class B没有被其他注解应用
      // 则class B继承了class A的注解@MyAnnotation
      public class B extends A {
      
      }
  • 自定义注解

    1. 注解的定义格式:通过@interface关键字自定义

      public @interface MyAnnotation {
      
      }
      // 这样就定义了一个注解了

      注解本质上就是一个接口,该接口默认继承Annotation接口

      public interface MyAnnotation extends java.lang.annotation.Annotation {}

    2. 注解的属性

      注解的属性其实就是注解接口中的抽象方法,只是叫做属性,不叫方法

      public @interface MyAnnotation {
          int id();
          String name();
      }// 这个注解有两个属性:id 和 name

      注解的属性是用无参的方法的形式来声明的,方法名就是属性名,比如上面的id和name,方法返回值就是属性的类型(下面介绍有多少种类型)

    3. 注解属性的类型

      属性的类型(方法的返回值) 有以下几种取值:

      • 基本数据类型(int,double之类)
      • String
      • 枚举
      • 注解
      • 以上类型的数组
    4. 注解属性的赋值

      属性赋值的格式是:注解(属性名1=value1,属性名2=value2...),用逗号分隔。

      在定义了属性之后,在使用注解的属性时需要赋值,有以下三种情况:

      • 定义属性时,可以使用default关键字给属性设置默认值,那么在使用属性时可以不赋值。
    • 如果只有一个属性需要赋值,并且属性名字为value,则可以省略value,直接赋值。
      • 数组赋值时,值用花括号{}包裹,如果数组只有一个值,则花括号可以省略。
    public @interface MyAnnotation {
        int id() default 0;
        String name();
    }// 这个注解有两个属性:id 和 name
    
    // 使用注解
    @MyAnnotation(id=1,name="zhangsan")
    public class A {
    }
    1. 获取注解

      获取某个对象上的所有注解,需要使用反射技术。

      注意:反射的时间成本比较高,所以注解的使用需要慎重。

      主要步骤有3个:

      • 获取注解定义的那个对象(类,方法,成员变量,对应为Class,Method,Field)
      • 获取指定的注解:
        • <T extends Annotation> getAnnotation(Class<T> annotationClass):返回指定类型的注解,如果不存在返回null
        • Annotation[] getDeclaredAnnotations(): 返回该元素上的所有注解
      • 调用注解中的抽象方法获取配置的属性值

      还有一个API,这个方法在是Class类对象的成员方法,用于某个类是否应用了某个注解:

      public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

四.注解实例

  1. 注解的获取

    import java.lang.annotation.*;
    
    /**
     * 定义一个注解
     * 注解在程序运行时使用需要加上@Retention(RetentionPolicy.RUNTIME)
     */
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
        // 定义两个属性
        int id() default -1;
        String type();
    }
    import java.lang.reflect.*;
    
    /**
     * 定义一个被注解MyAnnotation应用的类
     */
    @MyAnnotation(id=1,type="Class")
    public class ClassA {
    
        // 注解作用于成员
        @MyAnnotation(id=2,type="Field")
        public int field;
    
        // 注解作用于方法
        @MyAnnotation(id=3,type="Method")
        public void method() {
    
        }
    
        public static void main(String[] args) throws NoSuchFieldException, SecurityException, NoSuchMethodException {
            // 1. 获取类上的注解
            // 先判断类是不是应用了该注解
            boolean flag = ClassA.class.isAnnotationPresent(MyAnnotation.class);
            // 如果应用了,获取他的属性
            if(flag) {
                MyAnnotation annotation = ClassA.class.getAnnotation(MyAnnotation.class);
                int id = annotation.id();
                String type = annotation.type();
    
                System.out.println("ClassA id: " + id);
                System.out.println("ClassA type: " + type);
                // 输出:
                // ClassA id: 1
                // ClassA type: Class
            }
            // 2. 获取成员变量上的注解
            // 先利用反射获取成员变量field
            Field f = ClassA.class.getField("field");
            flag = f.isAnnotationPresent(MyAnnotation.class);
            if (flag) {
                MyAnnotation annotation1 = f.getAnnotation(MyAnnotation.class);
                System.out.println("Field id: " + annotation1.id());
                System.out.println("Field type: " + annotation1.type());
                // 输出:
                // Field id: 2
                // Field type: Field
            }
            // 3.获取方法上的注解
            Method m = ClassA.class.getMethod("method");
            flag = f.isAnnotationPresent(MyAnnotation.class);
            if (flag) {
                MyAnnotation annotation2 = m.getAnnotation(MyAnnotation.class);
                System.out.println("Method id: " + annotation2.id());
                System.out.println("Method type: " + annotation2.type());
                // 输出:
                // Method id: 3
                // Method type: Method
            }
        }
    }
  2. 简单的测试小框架:测试类中的方法是否有问题

    执行加了注解的方法,如果有bug,就输出到log文件中。

    import java.lang.annotation.*;
    
    /**
     * 定义一个注解,用于方法上
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Check {
    
    }
    
    public class TestClass {
        @Check
        public void add(int a, int b) {
            System.out.println("a + b = " + (a + b));
        }
    
        @Check
        public void sub(int a, int b) {
            System.out.println("a - b = " + (a - b));
        }
    
        @Check
        public void div(int a, int b) {
            System.out.println("a / b = " + (a / b));
        }
    }
    import java.io.*;
    import java.lang.reflect.*;
    
    public class CheckClass {
        public static void main(String[] args) throws IOException {
            // 创建TestClass对象
            TestClass tc = new TestClass();
            // 获取Class对象
            Class<?> cls = tc.getClass();
            // 获取所有的方法
            Method[] methods = cls.getMethods();
    
            // 出错的次数
            int errorNum = 0;
            // log文件
            BufferedWriter bw = new BufferedWriter(new FileWriter("log.txt"));
    
            // 遍历所有的方法,有注解Check的方法执行
            for (Method m : methods) {
                // 判断是否有Check注解
                if (m.isAnnotationPresent(Check.class)) {
                    // 执行方法
                    try {
                        m.invoke(tc, 1, 0);
                    } catch (Exception e) {
                        // 将异常信息写入log文件
                        errorNum++;
                        bw.write(m.getName() + "出现异常了");
                        bw.newLine();
                        bw.write("异常类型为:" + e.getCause().getClass().getName());
                        bw.newLine();
                        bw.write("异常原因为:" + e.getCause().getMessage());
                        bw.newLine();
                        bw.write("------------------------------------");
                        bw.newLine();
                    }
                }
            }
            bw.write("本次测试一共出现了" + errorNum + "次异常");
            bw.newLine();
    
            bw.flush();
            bw.close();
        }
    }

    最后运行结果为:

    $ java CheckClass
    a + b = 1
    a - b = 1

    打开log.txt文件如下:

    div出现异常了
    异常类型为:java.lang.ArithmeticException
    异常原因为:/ by zero
    ------------------------------------
    本次测试一共出现了1次异常

Java 注解

原文:https://www.cnblogs.com/LucasBlog/p/12198887.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!