功能 :①编写文档 ③编译检查 自定义注解 注解的属性 元注解的使用 解析注解案列实现配置文件
注解(Annotation)定义: 1. JDK1.5之后的新特性 2. 说明程序的 3.使用注解:@注解名称
①编写文档
/*
* @author itcat
* @version 1.0
* @since 1.5
*/
public class AnnoDemo1 {
/*
* 计算两数的和
* @param a 整数
* @param b 整数
* @return 两数的和
*/
public int add(int a, int b ){
return a + b;
}
}
使用cmd javadoc AnnoDemo1.java 就可以生成Api文档 并且文档中含有 代码中 版本 作者等信息
使用javap 类名.class 反编译一个 字节码文件
③编译检查
1. @Override :检测被该注解标注的方法是否是继承自父类(接口)的
2. @Deprecated:该注解标注的内容,表示已过时. 但仍可以使用
3. @SuppressWarnings:压制idea的 警告 * 一般传递参数all @SuppressWarnings("all") 可在方法 和类上加
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
自定义注解
元注解
public @interface 注解名称{
属性列表;
}
枚举定义:
public enum Person {
P1,P2;}
1.注解本质上就是接口默认继承Annotation接口public interface MyAnno extends java.lang.annotation.Annotation {}
2.接口中 的抽象方法 称为属性 在使用时需要给 属性赋值 属性格式: 返回值类型 ();
3. 返回值要求: 1. 基本数据类型 2.String 3.枚举 4. 注解 5. 以上类型的数组
注解的属性
1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
public @interface MyAnno {
int value(); 返回值基本类型
String[] strs(); 返回值是数组
String name() default "张三"; 返回值可以指定
Person per(); 返回值是枚举
MyAnno2 anno2(); 返回值是注解
String[] strs();
}
注解使用 strs是数组 用{}来写
@MyAnno(value=12,per = Person.P1,anno2 =@MyAnno2,strs={"b","a"}) name有默认值可以不写
public class Worker {
public String name = "aaa";
public void show(){
}
}
元注解的使用
1.@Target:描述注解能够作用的位置
1. ElementType.TYPE:可以作用于类上
2. ElementType.METHOD:可以作用于方法上 3. ElementType.FIELD:可以作用于成员变量上
2.@Retention:描述注解被保留的阶段
1.@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
3.@Documented:描述注解是否被抽取到api文档中 当添加时,Api文档中的方法或类上面会展示 注解
4. @Inherited:描述注解是否被子类继承 添加时 添加注解的类的子类会自动继承父类的 注解
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnno3 {
}
注解的使用
@MyAnno3
public class Worker { Worker的子类会自动继承这些注解
@MyAnno3
public String name = "aaa";
@MyAnno3
public void show(){
}
}
解析注解案列实现配置文件
1.实现一个注解
@Target({ElementType.TYPE}) 允许加在类上
@Retention(RetentionPolicy.RUNTIME) 在运行阶段加载
public @interface Pro {
String className(); 返回一个类名
String methodName();} 返回一个方法名 注解的属性
@Promy(className = "reflect.day01.Person",methodNmae = "eat") 加在类上
public class ReflectTestzhujie {
public static void main(String[] args) throws Exception {
获取该类的字节码 文件
Class<ReflectTestzhujie> reflectTestzhujieClass = ReflectTestzhujie.class;
获取该类的 注解 对象
Promy annotation = reflectTestzhujieClass.getAnnotation(Promy.class);
调用注解类中的方法 返回类名或方法名
String className = annotation.className();
String methodNmae = annotation.methodNmae();
使用反射 加载该类进进内存
Class cls = Class.forName(className);
创建该类的对象
Object obj = cls.newInstance();
获取该类的方法
Method eat = cls.getMethod(methodNmae, String.class);
eat.invoke(obj,"屎");}
2.获取注解对象原理: 原理 是创建一个类实现该注解并且添加两个 方法.返回值为 注解中 填入的字符串值
public class ProImpl implements Pro{
public String className(){
return "cn.itcast.annotation.Demo1";
}
public String methodName(){
return "show";}}
反射 与注解 :
1.反射需要加载 配置文件中 的配置,需要用到 Properties集合 加载 配置文件,而Properties 需要传入一个文件地址
这个地址用 类构造器 来获取字符输入流对象
2.注解 是类名.class 获取 字节码文件 对象,再用这个对象 获得本类的注解对象 再调用注解自动生成的方法返回值
为要创建的 类名或要运行的方法名
反射注解综合案列
1.检测自己的各个方法 有没有问题 2.只有加上了 @check 这个注解,就可以对她进行检测 3.将异常原因及名字写入配置文件
1.创建注解
@Target(ElementType.METHOD) 只用来检测方法
@Retention(RetentionPolicy.RUNTIME)
public @interface check {
}
2.创建需要检测的类
public class CalculatorMy {
@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...");}
}
3.创建测试类
1.method.isAnnotationPresent(check.class) 判断是否有注解
public class TestCheck {
public static void main(String[] args) throws IOException {
创建计算器对象
CalculatorMy calculatorMy = new CalculatorMy();
通过getClass获取字节码文件对象
Class cls = calculatorMy.getClass();
反射获取所有方法
Method[] methods = cls.getMethods();
统计异常次数
int num=0;
创建字符 输出流对象
BufferedWriter bfw = new BufferedWriter(new FileWriter("Bug.log"));
for (Method method : methods) { 遍历方法依次执行方法 捕获异常
if (method.isAnnotationPresent(check.class)){ 判断方法是否有注解 有才执行
try {
method.invoke(calculatorMy);
} catch (Exception e) {
num++; 异常次数加一
bfw.write(method.getName()+"出现异常!");
bfw.newLine();
bfw.write("异常的名称:"+e.getCause().getClass().getSimpleName());
bfw.newLine();
bfw.write("异常的原因:"+e.getCause().getMessage());
bfw.newLine();
}}}
bfw.write("本次共出现: "+num+" 次异常");
bfw.flush();
bfw.close();}}