zoukankan      html  css  js  c++  java
  • 注解初学

    概述

    • 概念:说明程序的。给计算机看的。

    • 注释:用文字描述程序。给程序员看的。

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

    • 概念描述:

      • JDK 1.5之后的新特性
      • 说明程序的
      • 使用注解:@注解名称
    • 作用分类:
      ①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
      ② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
      ③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

    JDK内置注解

    • @Override:检测【被该注解标识】方法是否是继承自父类(接口)的。
    • @Deprecated:该注解标注的内容,表示已过时。
    • @SuppressWarnings:压制警告。
      • 一般传递参数 all: @SuppressWarnings("all")
    package com.my.annotation;
    
    @SuppressWarnings("all")
    public class AnnoDemo {
        @Override
        public String toString() {
            return super.toString();
        }
    
        @Deprecated
        public void show1() {
    
        }
    
        public void show2() {
    
        }
    
        public void demo() {
            show1();
        }
    }
    

    自定义的注解

    • 格式
      • 元注解
      • public @interface 注解名称{ 属性列表; }
    • 本质:注解本质上就是一个接口,该接口默认继承 Annotation接口
      • public interface MyAnno extends java.lang.annotation.Annotation {}
    • 属性:接口中的抽象方法
      • 要求:
        1. 属性的返回值类型有下列取值:
          • 基本数据类型
          • String
          • 枚举
          • 注解
          • 以上类型的数组
        2. 定义了属性,在使用时需要给属性赋值
          1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
          2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,在使用时直接定义值即可。
          3. 数组赋值时,值使用 {}包裹。如果数组中只有一个值,则{}可以省略。
    • 元注解:用于描述注解的注解
      1. @Target:描述注解能够作用的位置
        • ElementType取值:
          • TYPE:可以作用于类上。
          • METHOD:可以作用于方法上。
          • FIELD:可以作用于成员变量上。
      2. @Retention:描述注解被保留的阶段
        • @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到 class字节码文件中,并被 JVM读取到。
      3. @Documented:描述注解是否被抽取到 API文档中
      4. @Inherited:描述注解是否被子类继承

    在程序中使用(解析)注解

    获取注解定义的属性值

    使用方式:

    1. 获取注解定义的位置的对象(Class, Method, Field)
    2. 获取指定的注解
      • getAnnotation(Class)
    // 其实就是在内存中生成了一个该注解接口的子类实现类对象
    public class ProImpl implements Prp {
      public String className() {
          return "com.my.annotation.Student";
      }
      public String methodName() {
          return "eat";
      }
    

    调用注解中的抽象方法获取配置的属性值

    • 示例:
    public class Student {
    
        public void eat() {
            System.out.println("eat...food!");
        }
    }
    
    // -------------------------------
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /*
        描述需要执行的类名和方法名
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Pro {
        String className();
    
        String methodName();
    }
    
    // -------------------------------
    
    import java.io.InputStream;
    import java.lang.reflect.AnnotatedType;
    import java.lang.reflect.Method;
    import java.util.Properties;
    
    /*
        需求:写一个“框架”,在不改变该类的任何代码的前提下
             可以帮助我们创建任意类的对象,并且执行其中任意方法
         不使用配置文件,使用注解来完成
     */
    @Pro(className = "com.my.annotation.Student", methodName = "eat")
    public class ReflectPractise {
        public static void main(String[] args) throws Exception {
            // 1.解析注解
            // 1.1 获取该类的字节码文件对象
            Class<ReflectPractise> reflectPractiseClass = ReflectPractise.class;
            // 2.获取上边的注解对象
            /*
               其实就是在内存中生成了一个该注解接口的子类实现类对象
            public class ProImpl implements Prp {
                public String className() {
                    return "com.my.annotation.Student";
                }
    
                public String methodName() {
                    return "eat";
                }
             */
            Pro anno = reflectPractiseClass.getAnnotation(Pro.class);
            // 3.调用注解对象中定义的抽象方法,获取返回值
            String className = anno.className();
            String methodName = anno.methodName();
            // 将该类加载进内存
            Class cls = Class.forName(className);
            // 创建对象
            Object obj = cls.getConstructor().newInstance();
            // 获取方法对象
            Method method = cls.getMethod(methodName);
            // 执行方法
            method.invoke(obj);
        }
    }
    

    案例:简单框架测试

    • Calculator.java
    /*
        计算机类
     */
    public class Calcluator {
        // 加法
        @Check
        public void add() {
            String str = null;
            str.toString();
            System.out.println("1 + 0 = " + (1 + 0));
        }
    
        // 减法
        @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!");
        }
    
    }
    
    • Check注解
    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 {
    
    }
    
    • TestCheck.java
    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.创建计算机对象
            Calcluator c = new Calcluator();
            // 2.获取字节码文件
            Class cls = c.getClass();
            // 3. 获取所有的方法
            Method[] methods = cls.getMethods();
    
            int number = 0; // 记录异常出现的次数
            BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
    
            for (Method method : methods) {
                // 4. 判断方法上是否有指定的注解
                if (method.isAnnotationPresent(Check.class)) {
                    // 5. 有就执行
                    try {
                        method.invoke(c);
                    } catch (Exception e) {
                        // 6. 捕获异常
                        // 记录到文件中
                        number++;
                        bw.write(method.getName()+" 方法出现异常了!");
                        bw.newLine();
                        bw.write("异常的名称:"+e.getCause().getClass().getSimpleName());
                        bw.newLine();
                        bw.write("异常的原因:" + e.getCause().getMessage());
                        bw.newLine();
                        bw.write("----------------------------");
                        bw.newLine();
    
                    }
                }
            }
            bw.write("本次测试一个出现了"+number+"次异常.");
            bw.flush();
            bw.close();
        }
    }
    
    /*
    add 方法出现异常了!
    异常的名称:NullPointerException
    异常的原因:null
    ----------------------------
    div 方法出现异常了!
    异常的名称:ArithmeticException
    异常的原因:/ by zero
    ----------------------------
    本次测试一个出现了2次异常.
    */
    

    小结:

    1. 以后大多时候,我们会使用注解,而不是自定义注解。
    2. 注解给谁用?
      1. 编译器
      2. 给解析程序用
    3. 注解不是程序的一部分,可以理解为【注解】就是一个标签
  • 相关阅读:
    大话算法-排序-希尔排序
    Linux三剑客-awk
    Linux三剑客-sed
    大话算法-排序-冒泡排序
    大话算法-排序-选择排序
    删除Win10菜单中的幽灵菜单(ms-resource:AppName/Text )
    微信推送模板消息
    获取当前域名的根域
    MVC 全站开启缓存,缓解服务器的请求压力
    MVC 开启gzip压缩
  • 原文地址:https://www.cnblogs.com/rainszj/p/12188786.html
Copyright © 2011-2022 走看看