美文网首页
注解入门梳理

注解入门梳理

作者: Steff_Ma | 来源:发表于2021-11-27 14:31 被阅读0次
    1. 概念:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
    2. 概念描述:
      • 是一种注射机制
      • 是JDK5.0新引入的
      • 相比于注释:
        • 注释,给人看
        • 注解,给程序看
        • 都不属于程序都一部分
        • 都能用于生成JavaDoc
    package com.steff;
    
    /**
    *Javadoc注解演示
    *
    * @author steff
    * @since 2021.11.27
    * @version 1.0
    */
    
    public class Calc {
    
      /**
       *
       * @param a 整数
       * @param b 整数
       */
      public int add(int a, int b){
          return a + b;
      }
    }
    
    1. 作用分类:

      • 编写文档,通过代码里标识的注解,生成文档【javadoc生成Doc】
      • 编译检查,通过代码里标识的注解,让编译器能够实现基本都编译检查【Override】
      • 代码分析,通过代码里标识的注解,对代码进行分析【使用反射】
    2. JDK中定义的注解:

      • Override:检测被该注解标注的方法是否是继承自父类的
      • Deprecated:被该注解标注的,表示已过时
      • SuppressWarnings: 编辑器中不展示警告
    
    package com.steff;
    
    /**
     * JDK 中预定义的一些注解
     *     * Override:检测被该注解标注的方法是否是继承自父类的
     *     * Deprecated:被该注解标注的,表示已过时
     *     * SuppressWarnings: 编辑器中不展示警告
     */
    public class Cat {
    
        @Override
        public String toString(){
            return super.toString();
        }
    
        @Deprecated
        public void meow(){
            System.out.println("Meow~");
        }
    
        public void miaow(){
            System.out.println("Miaow~");
        }
    
        public void speak(){
            this.miaow();
            this.meow();// IDE里面输入"this."后,候选的meow() 是有删除线的。
        }
        
        // 此方法会在编译器中被警告 "未被使用" / "void方法,无需return",
        // 但是我们可以通过SuppressWarnings注解不让IDE提示
        @SuppressWarnings("all")
        public void mew(){
            return;
        }
    }
    
    
    

    我们可以看下@Override这个注解是怎么定义的:

    package java.lang;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    
    1. 自定义注解:
      • 格式:

        • 元注解 // 可选项{@Type, @Target, @Retention}
        • public @interface 注解名称{}
      • 按照格式,我们来自定义一个最简单的注解:

        package com.steff;
        
        public @interface CustomAnnotation {
        }
        
      • 注解原理揭示:
        我们在 命令行 把CustomAnnotation.java编译为CustomAnnotation.class,
        再将CustomAnnotation.class反编译,即可得到这个注解,再java中原本的样子。

        >javac CustomAnnotation.java 
        >javap CustomAnnotation.class
        Compiled from "CustomAnnotation.java"
        public interface com.steff.CustomAnnotation extends java.lang.annotation.Annotation {
        }
        
        

        反编译的结果告诉我们,注解本质其实就是一个默认继承了java.lang.annotation.Annotation的接口。

      • 接下来我们再来看注解中属性

        • 注解属性的类型有以下几种:
          • 基本数据类型
          • String
          • 枚举
          • 注解
          • 以上类型组成的数组
              package com.steff;
        
              @Target(ElementType.TYPE)
              public @interface CustomAnnotation {
                  int time = 24*60*60; // 不了解定义普通变量有啥用,期待发掘
                  int times() default 7;
                  String describe();
                  Color color();
                  Override an();
                  String[] note();
              }
        
        
        • 属性的使用和赋值:
          • 使用注解时,需要给属性赋值,通过default关键字可以设默认值
          • 只有一个属性,且属性名为value,可以直接赋值,不用指定参数名
          • 数组赋值使用{}, 只有一个值时可以省略{}
        package com.steff;
        
        @CustomAnnotation(describe="买可乐", color=Color.YELLOW, note="Let's 买可乐", an=@Override)
        public class Person {
            public void buyCola(){
                System.out.println("买可乐");
            }
        }
        
      • 元注解 // 可选项

        • @Target(ElementType.TYPE) //描述注解能作用的位置
          TPYE -> 只能标注在类上
          METHOD -> 只能标注在方法上
          Field -> 只能标注在成员变量上?
        • @Retention(RetentionPolicy.RUNTIME) // 描述注解被保留的阶段
          • RUNTIME -> 运行时
          • CLASS -> 字节码
          • SOURCE -> 源码
        • @Documented // 描述注解是否被抽取到API文档中
        • @Inherited // 描述注解是否被子类继承
      • 由于不知道这玩意有啥妙用,此处我们不再Demo元注解的用法,有需要可以单独研究

      • 如何读取注解传入到数据?
       package com.steff;
      
       import java.util.Arrays;
      
       @CustomAnnotation(describe="买可乐", color=Color.YELLOW, note="Let's 买可乐", an=@Override)
       public class Person {
      
           public static void main(String[] args) {
      
              // 获取被标注类的字节码文件
             Class<Person> personClass = Person.class;
      
             // 获取注解对象
             CustomAnnotation customAnnotation = personClass.getAnnotation(CustomAnnotation.class);
      
             // 调用注解中的抽象方法,获取返回值
             System.out.println(customAnnotation.describe());
             System.out.println(Arrays.stream(customAnnotation.note()).iterator().next());
             System.out.println(customAnnotation.color());
         }
      
      }
      
      
    • 如何理解CustomAnnotation customAnnotation = personClass.getAnnotation(CustomAnnotation.class);
      • 其实就是在内存中实现了该注解接口的子类实现,并重写了注解中的抽象方法,返回了传入的参数:
    public class CustomAnnotationImpl implements CustomAnnotation{
    
            @Override
            public int times() {
                return 0;
            }
    
            @Override
            public String describe() {
                return "买可乐";
            }
    
            @Override
            public Color color() {
                return Color.YELLOW;
            }
    
            @Override
            public Override an() {
                return null;
            }
    
            @Override
            public String[] note() {
                return "Let's 买可乐".split("");
            }
    
            @Override
            public Class<? extends Annotation> annotationType() {
                return null; // 这个不会编了
            }
        }
    
    1. 程序中使用注解
      • 我们写个小练习,通过注解和反射测试Calc类中的方法。
    package com.steff;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Check {
    }
    
    package com.steff;
    
    
    public class Calc {
    
        @Check
        public void add(){
            System.out.println("1 + 0 = " + (1 + 0));
            throw new RuntimeException("你这个有Bug!");
        }
    
        @Check
        public void sub(){
            System.out.println("1 - 0 = " + (1 - 0));
        }
    
        @Check
        public void mul(){
            System.out.println("1 * 0 = " + (1 * 0));
        }
    
        @Check
        public void div(){
            System.out.println("1 / 0 = " + (1 / 0));
        }
    
        public void show(){
            System.out.println("永无Bug...");
        }
    }
    
    package com.steff;
    
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.reflect.Method;
    
    /**
     * 简单的测试框架
     *
     * 当主方法执行后,会自动进行被标记当所有方法(加了Check注解当方法)
     * 监测异常,并记录到文件中
     *
     */
    public class TestCheck {
    
        public static void main(String[] args) throws IOException {
            // 1 创建 待测对象
            Calc cal = new Calc();
            // 2 获取 字节码文件对象
            Class aClass = cal.getClass();
            // 3 获取 所有待测方法
    
            int count = 0; //出现异常的次数
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("Bug.txt"));
            bufferedWriter.write("--------------------------------------");
            bufferedWriter.newLine();
            for (Method m : aClass.getMethods()) {
                // 4 判断方法上是否有Check注解
                if(m.isAnnotationPresent(Check.class)){
                    try {
                        // 5 执行有注解的方法
                        m.invoke(cal);
                    } catch (Exception e) {
                        // 6 异常记录
                        count++;
                        bufferedWriter.write(m.getName() + " 出现异常!");
                        bufferedWriter.newLine();
                        bufferedWriter.write("异常名称:" + e.getCause().getClass());
                        bufferedWriter.newLine();
                        bufferedWriter.write("异常原因:" + e.getCause().getMessage());
                        bufferedWriter.newLine();
                        bufferedWriter.write("--------------------------------------");
                        bufferedWriter.newLine();
    
                    }
                }
                
            }
            // 7 测试结果
            bufferedWriter.write("本次一共出现异常" + count + "次。");
            bufferedWriter.flush();
            bufferedWriter.close();
        }
    
    
    }
    
    • 执行测试类主方法之后会在当前目录生成测试结果:
    --------------------------------------
    add 出现异常!
    异常名称:class java.lang.RuntimeException
    异常原因:你这个有Bug!
    --------------------------------------
    div 出现异常!
    异常名称:class java.lang.ArithmeticException
    异常原因:/ by zero
    --------------------------------------
    本次一共出现异常2次。
    

    内容来源链接

    相关文章

      网友评论

          本文标题:注解入门梳理

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