自定义注解
1.格式:
@元注解
public @interface 注解名称{}
2.本质:
注解本质上就是一个接口,该接口默认继承Annotatio而接口
public interface 注解名称 extends java.lang.annotation.Annotation{
属性列表(成员方法)
}
3.属性:
接口里面定义的抽象方法就称知为属性
package cn.itcast.annotation
public @interface MyAnno {
public abstract string show();//定义一个抽象方法
}
3.1要求:
*3.1.1,属性的返回值类型有下列取值
*基本数据类型 string
*枚举
*注解:以上类型的数组
*3.1.2,定义了属性,在使用时需要给属性赋值
*1,如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
*2·如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
*3,数组赋值时,值使用()包裹。如果数组中只有一个值,则{ }省略
4.元注解
:用于描述注解的注解
* @Target :描述注解能够作用的位置
例如
* ElementType取值:
* TYPE :可以作用于类上
* METHOD :可以作用于方法上
* FIELD可以作用于成员变量上
因为value 是String数组所以作用于类,方法,成员变量
- @Target :描述注解能够作用的位置
类型 | 描述 |
---|---|
ElementType.TYPE | 应用于类、接口(包括注解类型)、枚举 |
ElementType.FIELD | 应用于属性(包括枚举中的常量) |
ElementType.METHOD | 应用于方法 |
ElementType.PARAMETER | 应用于方法的形参 |
ElementType.CONSTRUCTOR | 应用于构造函数 |
ElementType.LOCAL_VARIABLE | 应用于局部变量 |
ElementType.ANNOTATION_TYPE | 应用于注解类型 |
ElementType.PACKAGE | 应用于包 |
ElementType.TYPE_PARAMETER | 1.8版本新增,应用于类型变量 |
ElementType.TYPE_USE | 1.8版本新增,应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型) |
例如:
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ApiLog {
}
- @Retention :描述注解被保留的阶段
类型 | 描述 |
---|---|
RetentionPolicy.SOURCE | 编译时被丢弃,不包含在类文件中 |
RetentionPolicy.CLASS | JVM加载时被丢弃,包含在类文件中,默认值 |
RetentionPolicy.RUNTIME | 由JVM 加载,包含在类文件中,在运行时可以被获取到 |
例如:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog {
}
- @Documented :表明该注解标记的元素可以被Javadoc 或类似的工具文档化
例如:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLog {
}
- @Inherited :所标记的类的子类也会拥有这个注解
例如:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ApiLog {
}
5.在程序使用(解析)注解
:获取注解中定义的属性值
1,获取注解定义的位置的对象 (class, Method,Field)
2,获取指定的注解
*getAnnotation(Class)
//其实就是在内存中生成了一个该注解接口的子类实现对象
public class ProImpl implements Prof public string className(){
return "cn.itcast.annotation. Demo1";
}
puflic string methodName(){
return "show";
}
3.调用注解中的抽象方法获取配置的属性值
6.自定义注解来测试代码
6.1新建注释Annotation1.java
package annotation;
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 Annotation1 {
}
6.2新建一个被测试类AnnoDemo1.java
package annotation;
//被测试的类
public class AnnoDemo1 {
@Annotation1
public void show_multiplication(){
System.out.println("0*1="+(0*1));
}
@Annotation1
public void show_division(){
System.out.println("0*1="+(1/0));
}
}
6.3新建测试功能类AnnotatedClass.java
package annotation;
import java.io.*;
import java.lang.reflect.Method;
//测试类
public class AnnotatedClass {
public static void main(String[] args) throws IOException {
//创建个AnnoDemo1对象
AnnoDemo1 a1=new AnnoDemo1();
//创建Class类对像
Class c1=a1.getClass();
//获取c1返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Method[] declaredMethods = c1.getDeclaredMethods();
int i=0 ,z=0;
System.out.println("测试了"+declaredMethods.length+"方法");
//创建字符输出流
BufferedWriter bufferedWrit=new BufferedWriter(new FileWriter("bug.txt"));
//遍历declaredMethods
for (Method declaredMethod : declaredMethods) {
//判断类中的方法是否有Annotation1该注释
if(declaredMethod.isAnnotationPresent(Annotation1.class)){
try {
i++;
//执行被测试类中的方法
declaredMethod.invoke(a1);
} catch (Exception e) {
z++;
//写入bug.txt
bufferedWrit.write(declaredMethod.getName()+"个方法有异常:"+e.getCause().getClass().getSimpleName());
//换行
bufferedWrit.newLine();
//System.out.println(declaredMethod.getName()+"个方法有异常:"+e.getCause().getClass().getSimpleName());
}
}
}
bufferedWrit.write("共有"+z+"个异常");
//关闭流
bufferedWrit.close();
}
}