注解
注解:注解(Annotation),也叫元数据。一种代码级别的说明,它是JKD1.5及以后版本映入的一个特性,与类,接口,枚举是在桶一个层次。它可以声明在包,类,字段,方法,局部变量,方法参数等的前面,用来对这些元素进行说明和注释。
注解:说明程序,给计算机看的。
注释:用文字描述程序,给人看的。
使用注解:@注解名称
作用分类:
- 编写文档:通过代码里的标识的注解生成文档[生成doc文档]
- 代码分析:通过代码里的标识的注解对代码进行分析[使用反射]
- 编译检查:通过代码里的标识的注解让编译器能够实现基本的编译检查[Override]
JDK中预定的注解
@Override:检查被该注解标注的方法是否继承父类(接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告
- 一般传递参数all @SuppressWarnings(“all”) 放在类的上面
自定义注解
格式:
- 元注解
- public @interface 注解名称{}
本质: 注解的本质就是一个接口,该接口默认继承Annotation接口
public @interface MyAnno{ }
- 以上通过javac编译文件之后javap反编译得到以下东西
public interface MyAnno extends java.lang.annotation.Annotation { }
属性:接口中可以定义的抽象方法
- 要求
- 属性的返回值类型
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
- 定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用default关键字给属性初始化值,则使用注解,可以不进行属性的赋值
- 如果只有一个属需要赋值,并且属性的名称是value,则value可以省略,直接定义即可
- 数组赋值时,值使用{}包裹。如果数组只有一个元素可以不用加括号
元注解:用于描述注解的注解
- @Target:描述注解能够作用的位置
- ElementType取值
- TYPE:可以作用于类
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量
- @Retention:描述注解被保留的阶段
- @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
- @Documented:描述注解是否被抽取到api文档中
- @Inherited:描述注解是否被子类继承
在程序中使用(解析)注解:获取注解中定义的属性值
- 获取注解定义的位置的对象(Class,Method,Field)
- 获取指定的注解
- getAnnotation(Class)// 其实就是在内存中生成了一个该注解接口的子列实现对象
- 调用注解的抽象方法获取配置的属性值
@Target({ElementType.TYPE})//只能作用在类上
@Retention(RetentionPolicy.RUNTIME)//在运行时可以加载进class并且被jvm读取
public @interface Pro {
String className();
String methodName();
}
@Pro(className = "annotation.Demo1",methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//2.获取上面的注解对象
Pro an = reflectTestClass.getAnnotation(Pro.class);//在内存中生成了一个该注解接口的子类实现对象
//3.调用注解对象的抽象方法,获取返回值
String className = an.className();
String classMethod = an.methodName();
System.out.println(className);
Class demoClass = Class.forName(className);
Object demo1 = demoClass.newInstance();
Method demoMethod = demoClass.getMethod(classMethod);
demoMethod.invoke(demo1);
}
}
案例
捕获一个类有Check注解的方法的异常
测试类
package annotation;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
public class TestCheck {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException {
Demo demo = (Demo) Class.forName("annotation.Demo").newInstance();
//获取字节码文件
Class cls= demo.getClass();
//获取所有方法
int num=0;
BufferedWriter bw = new BufferedWriter(new FileWriter("bug1.txt"));
Method[] methods = cls.getMethods();
for (Method method:methods){
//判断是否有注解
if(method.isAnnotationPresent(Check.class)){//isAnnotationPresent()放法判断是否存在注解
try {
method.invoke(demo);
}catch (Exception e) {
//记录到文件中
num++;
bw.write(method.getName()+"出现异常了\n");
bw.write("异常原因"+e.getCause()+"\n");
bw.write("------------------------------------------------\n");
}
}
}
bw.close();
}
}
注解
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 简单的测试框架
*
* 当主方法执行后,会自动自行检查的所有方法(Check注解的方法),判断方法是否有一次,记录到文件中
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//必须有这个元注解 不然运行的时候 JVM检查不到Check注解
public @interface Check {
}
Demo类
package annotation;
import com.sun.org.apache.bcel.internal.generic.LDIV;
public class Demo {
@Check
public void div(){
System.out.println(1/0);
}
@Check
public void p(){
System.out.println(100);
}
public static void main(String[] args) {
new Demo().div();
}
}