Java注解

一、概念

1. 定义

Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以 ‘@注解名’ 在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(注解)的访问。另外,你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件中出现。

2. 作用分类

如果要对于的作用进行分类,大致可分为三类:

  • 编写文档:通过代码里标识的注解生成文档。
  • 代码分析:通过代码里标识的注解对代码进行分析。
  • 编译检查:通过代码里标识的注解让编译器能实现基本的编译检查。


二、JDK中预定义的一些注解

@Override: 检测被该注解标注的方法是否是继承自父类(父接口)的。
@Deprecated: 该注解标注的内容,表示已过时。
@SuppressWarnings: 压制警告。一般传递参数 ‘all’ 。



三、自定义注解

1. 注解的格式及本质:

格式:
@元注解
public @interface 注解名称 { }

本质:
注解本质上就是一个接口,该接口默认继承Annotation接口。
public interface 注解名称 extends java.lang.annotation.Annotation( ) { }

2. 属性

接口中的抽象方法。

要求:
(1) 属性的返回值类型:

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以上类型对应的数组

(2)定义了属性,使用时需要给属性赋值:

  • 可以在定义属性时使用 ‘default’ 给属性初始化值。
  • 如果只有一个属性需要赋值,在赋值时可以直接写属性值即可,不需要写 ‘属性名 = 属性值’ 。
  • 数组赋值时,使用 ‘{ }’ 包裹,若数组中只需要赋一个值,则 ‘{ }’ 可以省略。

3. 元注解

用于描述注解的注解。

@Target: 描述注解能够作用的位置。
属性 ‘ElementType[ ] value’ 的常用属性值:

  • ElementType.TYPE:表示可以作用于类上。
  • ElementType.METHOD:表示可以作用于方法上。、
  • ElementType.FIELD:表示可以作用于成员变量上。

@Retention: 描述注解被保留的阶段。
属性 ‘RetentionPolicy value’ 的属性值:

  • RetentionPolicy.SOURCE:被描述的注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃。
  • RetentionPolicy.CLASS:被描述的注解被保留到class文件,但jvm加载class文件时候被遗弃。
  • RetentionPolicyRUNTIME:被描述的注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。(自定义注解一般取这个值)

@Documented: 描述注解是否被抽取到API文档中。

@Inherited: 描述注解是否被子类继承。



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

获取注解中定义的属性值。
步骤:

  1. 获取注解定义位置的字节码对象(Class、Field、Method、Constructor等)。
  2. 获取指定的注解(*.getAnnotation(Class))。’ * '表示步骤1中获取的对象。
  3. 调用注解中的抽象方法获取注解的属性值。

自定义注解:

package com.banmingi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @auther 半命i 2019/12/6
 * @description 描述需要执行的类名和方法名.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    String className();
    String methodName();
}

解析注解(注解使用的位置是在类上,所以用):

package com.banmingi.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
 * @auther 半命i 2019/12/6
 * @description
 */
@Pro(className = "com.banmingi.annotation.Demo1",methodName = "show")
public class AnnotationTest {
    public static void main(String[] args) throws Exception {
        //1. 解析注解
        //1.1. 获取该类的字节码文件对象
        Class<AnnotationTest> annotationTestClass = AnnotationTest.class;
        //1.2. 获取注解对象
        //其实就是在内存中去生成了该注解接口的子类实现对象(意思就是以下的Pro类实现了Pro注解(注解的本质是接口))
        Pro an = annotationTestClass.getAnnotation(Pro.class);
        //1.3. 调用注解对象中定义的抽象方法(属性),获取返回值
        String className = an.className();
        System.out.println(className); //com.banmingi.annotation.Demo1
        String methodName = an.methodName();
        System.out.println(methodName); //show
    }
}


五、使用注解实现简单的框架

设计一个框架,检测方法在运行的过程中是否出现异常。
定义Check注解:

package com.banmingi.annotation.demo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @auther 半命i 2019/12/6
 * @description
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}

被测试的类:

package com.banmingi.annotation.demo;

/**
 * @auther 半命i 2019/12/6
 * @description 自定义的计算器类
 */
public class Calculator {
    //加法
    @Check
    public void add() {
        Integer integer = null;
        integer.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...");
    }
}

解析程序:

package com.banmingi.annotation.demo;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @auther 半命i 2019/12/6
 * @description 简单的测试框架,当主方法执行后,会自动执行被检测的所有方法
 * 检测加了Check注解的方法,判断是否有异常,若无异常则执行方法,若有异常则把异常记录到bug.txt文件中
 */
public class TestCheck {
    public static void main(String[] args) throws IOException {
        //1. 创建计算器对象
        Calculator calculator = new Calculator();

        //2. 获取字节码文件对象
        Class cls = calculator.getClass();

        //3. 获取Calculator的所有方法
        Method[] methods = cls.getMethods();
        //出现异常的次数
        int num = 0;
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
        for (Method method : methods) {
            //4. 判断方法上是否有Check注解
            if(method.isAnnotationPresent(Check.class)) {
                //5. 有Check注解,执行方法
                try {
                    method.invoke(calculator);
                } catch (Exception e) {
                    //6. 捕获异常 把异常记录到bug.txt文件中
                    num++;
                    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("本次测试一共出现" + num + "次异常");

        bw.flush();
        bw.close();
    }
}

执行结果:
在这里插入图片描述
bug.txt:
在这里插入图片描述



六、小结

  1. 以后大多数时候,我们会使用框架的各种注解,而不是自定义注解。
  2. 注解给谁用:编译器、解析程序
  3. 注解并不是程序的一部分,可以理解为程序的一个标签。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值