注解
说明程序用,给计算机看的注释
功能
- 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
- 这个可以在命令行里面输入javadoc 文件名.java来获取
- 如果乱码就在结尾加上一个 -encoding utf-8 -charset utf-8
- 这个可以在命令行里面输入javadoc 文件名.java来获取
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
Jdk中预定义的一些注解
-
@Override :检测被该注解标注的方法是否是继承自父类(接口)
-
@Deprecated:该注解标注的内容,表示已过时
-
@SuppressWarnings:压制警告
一般传递参数all @SuppressWarnings(“all”)
在对应的方法前加上这个,最右边滚动条的那些黄色的警告就会全部消失
自定义注解
格式:
元注解
public @interface 注解名称()
这样就可以使用@Demo1这样一个注解了
注解本质上就是一个接口
注解的属性
因为注解本质上就是一个接口,所以肯定是能定义对应的成员方法的
注解的属性就是接口中的抽象方法
要求
- 属性的返回值类型
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
- 定义了属性后,在注释的时候要给这些属性赋值
- 如定义了一个 int show
- 在注释的时候就要加上 show = 1
- 如果不想赋值,可以用default来赋予初值
- 如果属性名叫value,并且只有一个属性,可以不写 属性名=属性值,直接写属性值
元注解
用于描述注解的注解
- @Target:描述注解能够作用的位置
- ElementType取值:
- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
- ElementType取值:
@Target({ElementType.TYPE})//表示该注解只能作用于类上
@Target({ElementType.METHOD})//表示该注解只能作用于方法上
@Target({ElementType.FIELD})//表示该注解只能作用于成员变量上
-
@Retention:描述注解被保留的阶段
- @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
-
表示运行时使用
@Retention(RetentionPolicy.RUNTIME)//表示该注解作用于运行时
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
-
@Documented:描述注解是否被抽取到api文档中
- 加了这个元注解的话这个就会被加载到api文档中
-
@Inherited:描述注解是否被子类继承
-
@Repeatable : 描述该注解是否可以重复使用,就是可不可以在同一对象上重复使用该注解
在程序中使用注解
- 获取注解定义的位置的对象 (Class,Method,Field)
- 获取指定的注解
- getAnnotation(Class)
- 其实就是在内存中生成了一个该注解接口的子类实现对象
- getAnnotation(Class)
- 调用注解中的抽象方法获取配置的属性值
@Pro(className = "po.Person",methodName = "eat")
public class 注解获取配置文件案例 {
public static void main(String[] args) throws Exception{
//解析注解
//获取该类的字节码文件对象
Class<注解获取配置文件案例> cls = 注解获取配置文件案例.class;
//如果这里是注解在方法上的就用方法.method来获取注解对象
//获取上面的注解对象
Pro an = cls.getAnnotation(Pro.class);
//上面这个过程就是在内存中生成了一个注解的实现对象
//调用注解对象中定义的抽象方法
String s = an.className();
String s1 = an.methodName();
}
}
用注解和反射完成的自定义测试程序
注解定义
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
String className() default " ";
}
@Check(className = "注解学习.Demo.Calculator")
@SuppressWarnings("all")
public class CheckTest {
public static void main(String[] args) throws Exception {
Class<CheckTest> checkTestClass = CheckTest.class;
Check check = checkTestClass.getAnnotation(Check.class);
String s = check.className();
if(!" ".equals(s)){
int number=0;
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("bug.txt"));
Class aClass = Class.forName(s);
//创建对象
Object o = aClass.newInstance();
/* //创建计算机对象
Calculator c = new Calculator();
//获取class对象
Class aClass = c.getClass();*/
//获取所有方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
if(method.isAnnotationPresent(Check.class)){
//这个判断条件是判断是否有Check.class这个注解
//有就会进入到我们的method ;
try {
method.invoke(o);
} catch (Exception e) {
//捕获异常
number++;
bufferedWriter.write(method.getName()+"方法出异常了");
bufferedWriter.newLine();
bufferedWriter.write("异常名称"+e.getCause().getClass().getSimpleName());
//这个是打印出异常的名称
bufferedWriter.newLine();
bufferedWriter.write("异常的原因是"+e.getCause().getMessage());
bufferedWriter.newLine();
bufferedWriter.write("----------------");
}
}
}
System.out.println("运行完成");
bufferedWriter.write("本次运行共出现"+number+"次异常");
bufferedWriter.flush();
bufferedWriter.close();
}
else{
System.out.println("运行失败,未输入对应测试用全类名");
}
}
}