遗失的藏宝图.
1、JDK中预定义的一些注解
@Override : 检测被该注解标注的方法是否继承自父类
@Deprecated : 该注解标注的内容,表示已过时
@SuppressWarnings : 压制警告
一般传递参数all @SuppressWarnings(“all”)
2、自定义注解
- 格式
元注解
public @interface MyAnoo {
属性列表
}
- 本质
//通过 javap myAnoo.class 反编译可以得到
public interface com.yhw.MyAnoo extends java.lang.annotation.Annotation {}
//所以本质上注解就是个接口,默认继承Annotation
- 属性
- 接口中可以定义什么,注解中也可以
- 属性就是接口中抽象方法
// 要求
1.属性的返回值类型有下列取值
基本数据类型
String
枚举
注解
以上类型的数组
2.定义了属性,在使用时需要给属性赋值
1.如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不给属性赋值
2.如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
3.数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
- 元注解
// 用于描述注解的注解
常见的
1.@Target:描述注解能够作用的位置
ElementType.TYPE 作用在类上
ElementType.METHOD 作用在方法上
ElementType.FIELD 作用在变量上
2.@Retention:描述被描述的注解被保留的阶段 硬盘 内存 运行时
RetentionPolicy.RUNTIME 当前被描述的注解,会保留到class字节码中,并被JVM读取到
3.@Documented:描述注解是否被抽取到api文档中
4.@Inherited:描述注解是否被子类继承
- 举例
//依次作用在类、方法、变量上
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
//在程序运行时生效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnoo {
int value() default 18 ;
Person per();
String name() default "张三";
String[] strs();
}
public class Person {
private String name;
private int age;
public void eat() {
System.out.println("吃啥呢??");
}
}
@MyAnoo(value=12,per=Person1,strs="史莱克")
public class Woreker{
}
3、解析注解
3.1、步骤
1 获取被加注解的位置的对象
由于注解可以加在 类 成员方法 成员变量上
对应的 可以 获得 Class Method Filed 对象
2 获取指定的注解
getAnnotation(Class 注解名)
//其实就是在内存中生成了一个该注解接口的子类实现对象
/*
public class MyAnooImpl implements MyAnno{
pubic String className(){
return "com.yhw.pojo.Person"
}
pubic String classMethod(){}
return "eat"
}
*/
3 调用注解中的抽象方法获取配置的属性值
3.2、简单实现
- pojo
public class Person {
private String name;
private int age;
public void eat() {
System.out.println("吃啥呢??");
}
}
- 注解
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 MyAnoo {
String className();
String classMethod();
}
- 测试
import java.lang.reflect.Method;
@MyAnoo(classMethod = "eat", className = "com.yhw.pojo.Person")
public class ReflectTest2 {
public static void main(String[] args) throws Exception {
//1.获取当前类的字节码文件
Class<ReflectTest2> aClass = ReflectTest2.class;
//2.获取注解对象
//其实就是在内存中生成了一个该注解接口的子类实现对象
/*
public class MyAnooImpl implements MyAnno{
pubic String className(){
return "com.yhw.pojo.Person"
}
pubic String classMethod(){}
return "eat"
}
*/
MyAnoo myAn = aClass.getAnnotation(MyAnoo.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String className = myAn.className();
String classMethod = myAn.classMethod();
System.out.println(classMethod);
System.out.println(className);
//4.通过反射实例化对象,调用方法
//通过类的全路径加载类的Class对象
Class clazz = Class.forName(className);
//通过Class对象new一个实例
Object newInstance = clazz.newInstance();
//通过类的Class对象得到方法对象
Method method = clazz.getMethod(classMethod);
//通过得到方法对象invoke实例对象,实现方法的调用
Object obj = method.invoke(newInstance);
}
}
4、测试框架
通过给要测试的对象方法上加注解,达到自动测试效果,输出测试文件
- 被测试类
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("看看你");
}
}
- 注解
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 {
}
- 测试
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.lang.reflect.Method;
public class TestCheck {
public static void main(String[] args) throws Exception {
//1.创建要测试的类对象
Calculator cal = new Calculator();
//2.得到对象的方法对象
Method[] methods = cal.getClass().getMethods();
int number = 0; //出现异常的次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
//3.判断方法上是否有Check注解
for (Method method : methods) {
//4如果有注解则执行方法,抓取异常
if (method.isAnnotationPresent(Check.class)) {
//5有就执行
try {
method.invoke(cal);
} 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();
}
}