JavaWeb——注解

注解的介绍

注解的概念

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

注解的分类

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

        JDk中预定义了许多注解,我们在编写代码中经常用到的有 :@Override,用于检测该注解的方法是否是继承子父类接口; @Deprecated,该注解标识的内容会被系统认定为过期方法或过期类。通俗的将就是原有的方法已经在性的JDK版本中得到升级,旧的方法考虑到,某些用户正在用老版本的jdk不兼容新的方法,便保留老方法标识为已过期。具体表现形式就是在方法名中划一横,但其功能还是能够使用的。@SuppressWarning:压制警告,一般传参all。用于消除程序中的无用警告。

自定义注解介绍

        注解除了JDK预定义的注解之外,我们还可以自己定义低级的注解。注解定义的格式如下:

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

        我们同构将上述代码文件的字节码文件进行反编译我们会发现,注解的本质就是一个接口,该接口默认继承了Annotation接口而已。

                接口中的成员变量等我们称之为属性注解的属性是有要求的:

        1.属性返回值类型只能是下面类型
                    *基本数据类型
                    *String
                    *枚举
                    *注解
                    *以上类型的数组
         2.定义了属性,在使用注解时要给属性赋值
                    *如果定义属性时,使用default关键字给属性默认初始化值,这在注释中,可以不給该属性赋值。
                    *如果只用一个属性需要赋值,并且属性名称时value,则value可以省略,直接定义数值
                    *数组赋值时,值使用大括号包裹。枚举赋值:per=枚举类名.枚举成员,注解赋值:a=@注解名

        如下代码就是没有赋值属性与赋值属性的注解的使用:

//自定义注解
package com.Javaweb.demoannotation;

public @interface MYzhu {
    int i();
    String name()default "张三";
}


//注解的调用代码
@MYzhu(i=1)//注解属性赋值
public class demo01 extends person{

}

        自定义注解除了注解内部的属性,还有一个就是元注解,元注解是用于描述注解的注解,其本质上还是注解。元注解一共有三个分别如下:

      1.@Target:描述注解能够作用的位置,属性只有一个value[]是一个枚举类型的数组
            ElementType取值:
                TYPE:可以作用于类上
                METHOD:可以作用于方法上
                FIELD:可以作用于成员变量上
       2.@Retention:描述注解被保留的阶段,属性只有一个value是一个枚举类型的赋值
            @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码中,并被JVM读取到
       3.@Documented:描述注解是否被抽取到API文档中
       4.@Inherited:描述注解是否能被子类继承

自定义注解的使用

        在前面我们介绍了反射,并举例使用反射实现任意类的的类名获取以及方法的调用,例子中是通过配置文件来实现字节码的获取。在这里注解能通过注解的属性实现类名方法名的获取,而且在实际运用中注解的使用更为方便。

        首先我们需要自定义注解,注解的属性有两个,一个是类名,一个是方法名。注解的定义范围是类或者方法。

//自定义注解
package com.Javaweb.demoannotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
* 描述执行的类名个方法名*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface pro {
    String className();
    String methodName();
}

        然后我们通过程序使用的注解获取注解定义的属性值,步骤如下

        1.获取注解定义位置的对象(class,methode,field)
        2.获取指定的注解getAnnotation(Class)
            其实就是在内存中生成一该注解接口的个子类对象
                public class PorImpl implements Pro(){
                    public String className(){
                        return "com.Javaweb.reflectman.person";
                    }
                     public String methodName(){
                        return "eat";
                    }
                }
        3.调用注解的中抽象方法获取配置的属性值

        实现代码如下:

package com.Javaweb.demoannotation;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Properties;

import static java.lang.Class.forName;

@pro(className = "com.Javaweb.reflectman.person",methodName = "eat")
public class demoExample {

    public static void main(String[] args) throws Exception {
        //1.获取注解
        //1.1获取该类的字节码文件对象
        Class<demoExample> re=demoExample.class;
        //2.获取上面的注解对象
        pro anntion= re.getAnnotation(pro.class);//其实是在内存中生成的一个该注解接口的子类实现对象
        //3.调用注解对象中的抽象方法,获取返回值
        String className=anntion.className();
        String methodName=anntion.methodName();
        //加载进内存
        Class cls= forName(className);
        //4.创建对象
        Object obj= cls.newInstance();//过时方法
        //5.获取对象方法
        Method me= cls.getMethod(methodName);
        //6.执行方法
        me.invoke(obj);

        //方法的注解解析
        demoExample de=new demoExample();
        de.p();
    }
    @pro(className = "com.Javaweb.reflectman.person",methodName = "eat")
    public void p() throws Exception {
        //获取该类的class文件
        Class re=demoExample.class;
        //获取该类被注解的方法
        Method p=re.getMethod("p");
        //生成注解对象
        pro c= p.getAnnotation(pro.class);
        //得到类路径以及方法名
        String name=c.className();
        String method=c.methodName();
        //将该类加载进内存
        Class cls =forName(name);
        //生成类对象
        Object obj=cls.newInstance();
        //获取方法对象
        Method m=cls.getMethod(method);
        //执行方法
        m.invoke(obj);
    }
}

        在代码中我们一共实现了两种不同位置的注解获取属性值,一个注解在类上,一个注解在方法上,后者比前者只是多了一步方法的获取而已。

练习题

        要求:实现下述代码中有注解部分的检测以及错误的抛出:

package com.Javaweb.demoannotation.test;

public class Calculator {
    @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 show(){
        System.out.println("永无bug....");
    }
}

        实现方法:

package com.Javaweb.demoannotation.test;

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

/*
* 简单的测试框架
* 当主方法执行后,会自动执行被检查的所有方法(加了check注解的方法),判断是否有异常,自动记录到文档中*/
public class techercheck {
    public static void main(String[] args) throws Exception {
        //1.创建计算机对象
        Calculator cal=new Calculator();
        //2.获取计算机字节码问价
        Class cs=cal.getClass();
        //3.获取字节码文件的所有方法
        Method[] m= cs.getMethods();
        int num=0;//出现异常的次数
        BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt"));//创建文件抛出异常
        for (Method method : m) {
            //4.判断方法上是否有check注解
            if(method.isAnnotationPresent(Check.class)){
                //有,就执行
                try {
                    method.invoke(cal);
                } catch (Exception e) {
                    e.printStackTrace();
                    //6.捕获异常
                    //7.记录到文件中
                    num++;
                    bw.write(method.getName()+"方法出异常了");
                    bw.newLine();
                    bw.write("异常的名称:"+e.getCause().getClass().getSimpleName() );
                    bw.newLine();
                    bw.write("异常的原因:"+e.getCause().getMessage());
                    bw.write("==================================");
                }
            }
        }
        bw.write("本次测试异常次数:"+num);
        bw.flush();
        bw.close();


    }
}

        最后的实现结果是抛出一个bug.txt文件记录所有的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值