Skip to content
Go back

3-注解

Published:  at  03:28 AM

注解

从JDK5开始,Java增加对元数据的支持,也就是注解,注解是一种代码级别的说明。注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。

作用分类

JDK内置注解

自定义注解

//自定义注解的格式

元注解...
public @interface 注解名称(){}

注解的本质

注解本质就是一个接口,该接口默认继承java.lang.annotation.Annotation接口

下面的内容就是通过将public @interface MyAnnotation { }经过编译与反编译后重新得到的Java文件,可以清楚的看到注解的本质

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

编译与反编译的过程 注解的本质

注解的属性

在注解接口中定义的抽象的成员方法

要求

属性的返回值类型只能是下列取值:

定义属性后,在使用时需要给属性赋值(或者在定义时利用default()传入默认值)

如果只有一个属性需要赋值,且属性名为value,则value可以省略,直接传入值即可

数组赋值时,使用大括号{}包裹值,如果数组中只有一个值,大括号可以省略

元注解

用于描述注解的注解

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

获取注解中定义的属性值

首先获取注解定义位置的对象,因为注解可以定义在类,方法或成员变量上,所以需要获取对应变量,例如:注解定义在类上,就需要获取该类对象,然后通过类对象的getAnnotation方法获取到指定的注解,随后只需要调用注解的属性值(抽象方法)即可获取到我们所配置的属性值

定义注解:

/**
 * 描述需要执行的类名和方法名
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Pro {
    String className();
    String methodName();

}

调用注解并获取属性值

@Pro(className = "cn.ywrby.domain.Person",methodName = "MessageOfPerson")
public class ReflectTest2 {

    public static void main(String[] args) throws Exception {

        //解析注解
        //获取本类的字节码文件对象
        Class<ReflectTest2> MyCls=ReflectTest2.class;
        //获取本类指定的注解
        //其实就是在内存中生成一个该注解接口的子类实现对象,该子类复写了注解的属性,返回值就是我们定义注解时传入的值
        Pro annotation=MyCls.getAnnotation(Pro.class);
        //调用注解对象中定义的抽象方法(属性),获取返回值
        String className=annotation.className();
        String methodName=annotation.methodName();

        //加载该类进内存,并且创建对象
        Class cls=Class.forName(className);
        //创建对象
        Object object=cls.getDeclaredConstructor().newInstance();
        //获取方法对象
        Method method=cls.getMethod(methodName);
        //执行方法
        method.invoke(object);
    }
}

简单案例:完成一个简单的测试框架

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}

使用注解

public class Calculator2 {

    @Check
    public void add(){
        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 ignore(){
        System.out.println("永不报错,不被检查");
    }
}

进行测试

/**
 * 简单的测试框架
 *
 * 主方法执行后,自动检测所有加上@Check注解的方法,判断方法有无异常,并记录在文件中
 */
public class Calculator2Test {


    public static void main(String[] args) throws IOException {
        int errorNum=0;   //出现异常的次数
        BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt"));

        //创建Calculator2对象
        Calculator2 cal=new Calculator2();
        //获取字节码文件对象
        Class<Calculator2> cls=Calculator2.class;
        //获取所有方法
        Method[] methods=cls.getMethods();
        //判断是否有@Check注解
        for(Method method:methods){
            //isAnnotationPresent方法判断当前方法上是否有指定的注解
            if(method.isAnnotationPresent(Check.class)){
                //存在则执行方法,不存在则不执行该方法
                try {
                    method.invoke(cal);
                } catch (Exception e) {
                    //发现异常,捕获异常并记录在文件中
                    errorNum+=1;
                    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("本次一共出现"+errorNum+"个异常");
        bw.flush();
        bw.close();
    }
}

运行效果

//窗口显示结果
1+0=1
1-0=1
1*0=0
//bug.txt文件中显示内容
div方法出现异常!
异常的名称:ArithmeticException
异常的原因/ by zero
--------------------------------------
本次一共出现1个异常

小结


Suggest Changes

Previous Post
4-JDBC
Next Post
2-反射