java之注解

下面来说一下注解形式:

既然注解是接口,那么注解里面就有抽象方法,也就是我们常说的属性,那接口里面的方法能返回些啥啊?好奇不?

基本数据类型?ok

String类型?ok

枚举也可以?ok

注解?没想到吧,注解里面还可以返回注解,没想到吧,兄弟

还有一种类型void?这个可不行,没有具体定义

总结一下:

那么下面我先来说一下预定义注解:

预定义注解:就是jdk已经给我们设计好的注解接口,都有啥?

如下,也就是我们写程序常常见到的一些东西:

上面就是判断是不是重载的父类的方法,是不是过时,还可以屏蔽无端的警告信息

下面说一下元注解:

定义注解的注解:

这玩意,就是告诉编译器,你这个自定义注解可以在什么地方用,可以保留到程序什么阶段

大致就是上面这些东西,给注解用的,随便看一下,点进去它的源程序看一下:

里面是一个变量名为value的数组,这个返回类型也是给我们设计好的,但是你要传入的是啥值不是也是设计好的嘛,我们只需要去调用设计好的属性就ok.这里还需要说明一点就是,属性名如果是value,可以省略不写

 下面重点说说,注解的用途:

这玩意,首先一看,我们用系统给我们设计的用的倒是挺好哈,所以,首先我们是要会用,就是会用别人给我们设计的,而不是我们自己设计的。

完了之后,我们可以用注解来替换我们的配置文件,这样倒是也常用,方便嘛,你想啊,配置文件也是属性值,注解也是属性,值,而配置文件我们每次去引用是不是挺费劲,又要找到Class对象,又要得到资源位置,再加载到Properties对象中

之前做反射的时候,我想利用配置文件中的全类名,与方法名,来构造一个对象,然后执行一个方法,我现在不用配置文件了,用注解来做,于是我设计一个Pro注解类:

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)//保留到字节码文件中,并被jvm读取到
public @interface Pro {

    String className();
    String methodName();

}

然后在看下一下主体代码:

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

@Pro(className="domain.Person",methodName = "eat")
public class ReflectTest {
    public static void main(String[] args) throws IOException, NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //主要是去找到注解里面的属性内容
        //获取该类的字节码对象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;
        //获取注解对象,内部是传入一个注解的字节码文件类
        Pro an = reflectTestClass.getAnnotation(Pro.class);
        //调用注解对象中抽象方法,获取返回值
        String className = an.className();
        String methodName = an.methodName();

        //先得到对象的字节码类文件
        Class obj = Class.forName(className);
        //创建对象去调用方法
        Constructor cons = obj.getConstructor();
        //然后实例化一个对象
        Object obj1 = cons.newInstance();
        //获取方法
        Method method = obj.getMethod("eat",String.class);
        method.invoke(obj1,"pingguo");
    }
}

 上面调用了Class类中下面的方法:

这里简单来说一下,为什么,Class类,Field类,Method类实现的对象都可以调用getAnnotation()方法,直接上图:

 

很明显就是他们都实现了AnnotatedElement这个接口 ,而这里面有一个得到注解类对象的方法,传入注解类的字节码对象就行

最后,我们可以用注解来标注成员方法,然后根据是否有注解信息,来验证程序数据是否合理

话不说直接看代码:

一个计算器工具类:

package demo;

/**
 * 计算器类
 */
public class Calculator {

    //加法
    @Check
    public void add(){
        String str = null;
        int len = str.length();
        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("no bug...");
    }

}

 写一个注解类:

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 Check {
}

上面这个注解类注意它的保留位置,如果只是在源代码阶段,那么加载到内存我们就获取不了,所以让它停留的时间尽可能长一点啊。

下面看我们测试代码:

package demo;

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

public class TestCheck {


    public static void main(String[] args) throws IOException {
        //1.创建计算器对象
        Calculator c = new Calculator();
        //2.获取字节码文件对象
        Class cls = c.getClass();
        //3.获取所有方法
        Method[] methods = cls.getMethods();

        for(Method method : methods) {
            System.out.println(method);
        }
        int number = 0;//出现异常的次数
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug2.txt"));


        for (Method method : methods) {
            Check check = method.getAnnotation(Check.class);
            //4.判断方法上是否有Check注解
            if(check != null){
                System.out.println("进来了几次");
                try {
                    method.invoke(c);
                    //这个位置你知道出现什么异常?其实不知道,也就是会出现多种可能的异常
                    //不知道啥异常,我用Exception来捕获
                } catch (Exception e) {
                    //把这个异常信息写入一个日志文件
                    number++;
                    //真实的异常类名(带包)getCause()会得到一个真实的异常对象(当我们不知道会出现什么异常的时候可以使用)
                    bw.write("异常类名:" + e.getCause().getClass().getName());
                    bw.newLine();
                    bw.write("异常原因:" + e.getCause().getMessage());
                    bw.newLine();
                    bw.write("------------");
                    bw.newLine();
                }
            } else {
                System.out.println("方法没有注解");
            }
        }

        bw.write("本次测试一共出现 "+number+" 次异常");
        bw.flush();
        bw.close();
    }

}

多说两句,如果是这种方式判断是否注解,这种方法要学会去找:

 下面看一下这个异常问题:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值