介绍
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注解不是程序的一部分,可以理解为注解就是一个标签。主要是给编译器、解析程序用。
概念描述:
- JDK1.5之后的新特性
- 说明程序的
- 使用注解:@注解名称
作用分类:
- 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
JDK中预定义的一些注解
- @Override :检测被该注解标注的方法是否是继承自父类(接口)的
- @Deprecated:该注解标注的内容,表示已过时
- @SuppressWarnings:压制警告
- 一般传递参数all @SuppressWarnings("all")
自定义注解
格式
元注解
public @interface 注解名称{
属性列表;
}
本质:注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation {}
属性:接口中的抽象方法
属性的返回值类型有下列取值
基本数据类型、String、枚举、注解、前面4种类型的数组
定义了属性,在使用时需要给属性赋值
1、如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
2、如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
3、数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
元注解:用于描述注解的注解
1、@Target:描述注解能够作用的位置
ElementType取值:
TYPE:可以作用于类上
METHOD:可以作用于方法上
FIELD:可以作用于成员变量上
2、@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
3、@Documented:描述注解是否被抽取到api文档中
4、@Inherited:描述注解是否被子类继承
自定义注解应用样例1
注解定义
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 描述定义的类名和方法名 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Pro { String className(); String methodName(); }
注解解析和使用
import java.lang.reflect.Method; @Pro(className = "com.jerrylee.reflect.domain.Student", methodName = "study") public class AnnoDemo01 { public static void main(String[] args) throws Exception { // 获取类的字节码 Class<AnnoDemo01> cls = AnnoDemo01.class; // 获取上边的注解对象 --其实就是在内存中生成了一个实现该注解接口的子类对象 Pro pro = cls.getAnnotation(Pro.class); // 调用注解对象中定义的抽象方法,获取返回值 String className = pro.className(); String methodName = pro.methodName(); // 通过反射获取类,方法,并调用 Class cls2 = Class.forName(className); Method method = cls2.getMethod(methodName); Object obj = cls2.newInstance(); method.invoke(obj); } }
自定义注解应用样例2
自定义注解
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 Check { }
测试框架代码
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 简单的测试框架 * 当主方法执行后,加了@Check注解会执行测试并输出结果到文件 */ public class TestCheck { public static void main(String[] args) throws IOException { Calculator c = new Calculator(); Class cls = c.getClass(); Method[] methods = cls.getMethods(); // 记录异常个数 int number = 0; // 写文件buffer BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt")); for (Method method : methods) { if (method.isAnnotationPresent(Check.class)) { try { method.invoke(c); } catch (Exception e) { // 捕获异常 number++; bw.write(number + ":" + method.getName() + "方法异常了"); bw.newLine(); bw.write("异常名称:" + e.getCause().getClass().getSimpleName()); bw.newLine(); bw.write("异常原因:" + e.getCause().getMessage()); bw.write("----------------"); bw.newLine(); } } } bw.newLine(); bw.write("本次测试总共有"+number+"异常"); bw.flush(); bw.close(); } }
测试类
public class Calculator { @Check public void add() { 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)); } @Check public void testStr() { String str = null; System.out.println(str.toString()); } public void show() { System.out.println("No bug forever."); } }
输出bug.txt
1:div方法异常了 异常名称:ArithmeticException 异常原因:/ by zero---------------- 2:testStr方法异常了 异常名称:NullPointerException 异常原因:null---------------- 本次测试总共有2异常
浙公网安备 33010602011771号