注解
一、概念
**注释:**用文字描述程序的。给程序员看的。
**注解:**说明程序的,给计算机看的。
**概念:**注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,没有加,则等于没有任何标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无何种标记,看你的程序有什么标记,就去干相应的事,标记可以加在包、类,属性、方法,方法的参数以及局部变量上。
作用:
- 编写文档:通过代码里标书的注解生成文档【生成文档doc文档】。
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】。
- 编译检查:通过代码里标识的注解让编译器恩呢狗狗实现基本的编译检查【Override】.
二、JDK中内置注解
1.@Override:检测该注解标注的方法是否继承自父类。
2.@Deprecated:该注解标注的内容,已过时。
3.@SuppressWarnings:压制警告。
三、自定义注解
1.格式
元注解
public @interface 注解名称{}
2.本质
反编译:javap MyAnno.class
注解本质上就是一个接口,默认继承Annotation接口。public interface MyAnno extedns java.lang.annotation.Annotation{}
3.属性
接口中可以定义的成员方法(抽象方法)。
要求:
(1)属性的返回值类型
基本数据类型
String
枚举
注解
以上类型的数组。
(2)定义了属性,在使用时需要赋值
-
@MyAnno(age = 12, name = "张三",per = Person.p1,anno2 = @MyAnno2,strs={"abc","def"});
五种类型属性赋值。 -
如果定义属性时使用Default进行初始化,咋使用该注解时可以不赋值。
-
如果只有一个属性需要赋值,并且属性的名称是value,则该属性名称可以省略,直接写值即可。
@MyAnno(12);
-
数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略。
4.元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
- TYPE:作用于类上
- METHOD:作用于方法上
- FIELD:作用于成员变量上
@Target(value = {ElementType.TYPE,ElementType.METHOD})//只能作用于类,方法
public @interface MyAnno3{
}
@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME)//当前被描述的注解会保留到class字节码文件中,并被JVM读取到。
public @interface MyAnno3{
}
@Documented:描述注解是否被抽取到API文档中。
@Documented//注解被保留到api文档中
public @interface MyAnno3{
}
@Inherited:标识注解是否被子类继承。
@Inherited//子类继承父类的注解
public @interface MyAnno3{
}
四、解析注解
解析注解主要是获取注解中定义的属性值。
- 获取注解定义位置的对象(Class,Mehtod,Field)
- 获取指定的注解:getAnnotation(class)
- 调用注解中的抽象方法来获取配置的属性值
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro{
String className();
String methodName();
}
@pro(className="com.yuwendeng.Demo",methodName="show")
public class ReflectTest{
public static void main(String[]args){
Class<ReflectTest> ReflectTestClass= ReflectTest.class;
//获取上边的注解对象,其实就是在内存中生成了一个该注解接口的子类实现对象,见下一程序代码
Pro an = ReflectTestClass.getAnnotation(pro.calss);
//调用注解对象方法,获取属性值
String className = an.className();
String methodName = an.methodName();
}
}
public class ProImpl implements Pro{
public String className(){
return "自己在注解上传入的属性值";
}
public String methodName(){
return "自己在注解上传入的属性值";
}
}
五、案例
简单的测试框架,当主方法执行后,会自动检测所有方法(加了check的方法)
public class TestCheck{
public static void main(String[]args){
Calculator c = new Calculator();
//获取字节码对象
class cls = c.getClass();
//获取所有方法
Method[] methods = cls.getMethods();
int number = 0;//异常出现次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
// 判断方法上是否有check注解
for(Method method:methods){
//有,执行
if(method.isAnnotationPresent(Check.class)){
try{method.invoke(c);
}catch(Exception){
//捕获异常,catch中记录文件
number++;
bw.writer(method.getName()+"方法异常了);
bw.newline();
bw.writer("异常的名称"+e.getCause().getClass().getSimpleName());
bw.newline();
bw.writer("异常的原因"+e.getCause().getMessage());
bw.newline();
}
}
}
bw.close();
}
}