注解概念
注解的本质就是一个继承了 Annotation 接口的接口。在反编译一个注解类(javap命令)时,就可以发现。
注解可以理解为一种特别的注释,主要是给编译器看的。
JDK中预定义的一些注解
常用的有下面三个:
- @Override :检测被注解标注的方法是否为继承自父类(接口)的
- @Deprecated:表示被注解的内容已经过时
- @SuppressWarnings:压制警告 一般传递参数all @SuppressWarnings(“all”)
自定义注解
元注解
- @Target:注解的作用目标。用于指明被修饰的注解最终可以作用的目标是谁,也就是指明,你的注解到底是用来修饰方法的?修饰类的?还是用来修饰字段属性的。
- @Retention:注解的生命周期
- RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
- RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
- RetentionPolicy.RUNTIME:永久保存,可以反射获取
- @Documented:注解是否应当被包含在 JavaDoc 文档中
- @Inherited:是否被子类继承该注解
package cn.xgblack.javastudy.annotation;
import java.lang.annotation.*;
/**
* ElementType
* TYPE作用于类上
* METHOD方法上
* Field成员变量上
* RetentionPolicy
*/
@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MYAnno2 {
}
注解的使用
- getAnnotation:返回指定的注解
- isAnnotationPresent:判定当前元素是否被指定注解修饰
- getAnnotations:返回所有的注解
- getDeclaredAnnotation:返回本元素的指定注解
- getDeclaredAnnotations:返回本元素的所有注解,不包含父类继承而来的
使用注解创建指定对象并调用指定方法
自定义一个注解:
package cn.xgblack.javastudy.annotation;
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 Pro {
String className();
String methodName();
}
建一个ReflectTest类:
package cn.xgblack.javastudy.annotation;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* @author 小光
* @date 2019/5/11 12:25
* className: ReflectTest
* description: 框架类,在不改变代码的前提下,可以帮助我们创建任意对象,并执行其中的方法
* 对象的全类名和需要执行的方法名定义在配置文件中
* 使用反射技术,加载类到内存
*
* ***************************************************************************
* Copyright(C),2018-2019,https://blog.xgblack.cn .All rights reserved.
* ***************************************************************************
*/
@Pro(className = "cn.xgblack.javastudy.domain.Student",methodName = "sleep")
public class ReflectTest {
public static void main(String[] args) throws Exception {
//解析注解
//获取该类的字节码文件
Class<ReflectTest> reflect = ReflectTest.class;
//获取上边的注解对象
Pro annotation = reflect.getAnnotation(Pro.class);
//调用注解对象中定义的方法
String className = annotation.className();
String methodName = annotation.methodName();
Class<?> aClass = Class.forName(className);
Object obj = aClass.newInstance();
Method method = aClass.getMethod(methodName);
method.invoke(obj);
}
}
这样做的好处就是,不需要改动大量代码,只需要在注解处修改要调用的类的全类名,修改方法名,其他的地方不需要任何修改。
利用注解进行异常检测
自定义一个注解Check
package cn.xgblack.javastudy.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
定义一个存在异常情况的Calculator类
package cn.xgblack.javastudy.demo;
import java.sql.SQLOutput;
/**
* @author 小光
* @date 2019/5/11 14:38
* className: Calculator
* description:
* ***************************************************************************
* Copyright(C),2018-2019,https://blog.xgblack.cn .All rights reserved.
* ***************************************************************************
*/
public class Calculator {
@Check
public void add(){
String str = null;
str.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 cn.xgblack.javastudy.demo;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* @author 小光
* @date 2019/5/11 14:37
* className: TestCheck
* description: 简单的测试框架
* 主方法执行后,会自动检测被加了注解的方法,
* <p>
* ***************************************************************************
* Copyright(C),2018-2019,https://blog.xgblack.cn .All rights reserved.
* ***************************************************************************
*/
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();
//出现异常的次数
int num = 0;
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
//4.判断方法上是否有Check方法,
if (method.isAnnotationPresent(Check.class)) {
//5.有就执行
try {
method.invoke(c);
} catch (Exception e) {
//6.捕获异常
//记录到文件中
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();
}
}
Calculator类中有两个地方会发生异常,一个是除0的异常,一个是空指针异常。运行之后,打开生成的bug.txt文件
退出登录?