三十七.注解
37.1 概述
Annotation表示注解,JDK1.5新特性
注解作用:对程序进行标准,可以给类增加额外的信息
注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。
Java中已经存在的注解
@Override:表示方法的重写
@Deprecated:表示修饰的方法已过时
@SuppressWarnings("all"):压制警告
第三方框架中提供的注解:比如:Junit
-
@Test 表示运行测试方法
-
@Before 表示在Test之前运行,进行数据的初始化
-
@After 表示在Test之后运行,进行数据的还原
37.2 自定义注解
//自定义注解
public @interface AnnotationDemo1 {
// 给name赋默认值。也可以不给默认值
// public String name() default "aaaa";
public String name();
public int age();
}
================================
//使用注解
@AnnotationDemo1(name = "aaaa",age=6666)
public class MyAnnotation {
@AnnotationDemo1(name = "aaaa",age=6666)
private String name;
private int age;
@AnnotationDemo1(name = "aaaa",age=6666)
public void method01(){
System.out.println("这是方法1");
}
public void method02(){
System.out.println("这是方法2");
}
}
特殊属性value:
当注解中只有"一个属性",并且属性名是"value",使用注解时,可以省略value属性名
代码示例:
//注解的定义
public @interface Anno2 {
public String value();
public int age() default 23;
}
//注解的使用
@Anno2("123")
public class AnnoDemo2 {
@Anno2("123")
public void method(){
}
}
37.3 元注解
元注解:注解注解的注解,即 可以写在注解上面的注解
@Target :指定注解能在哪里使用
@Retention :可以理解为保留时间(生命周期)
Target:
作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
可使用的值定义在ElementType枚举类中,常用值如下
- TYPE,类,接口
- FIELD, 成员变量
- METHOD, 成员方法
- PARAMETER, 方法参数
- CONSTRUCTOR, 构造方法
- LOCAL_VARIABLE, 局部变量
@Target(ElementType.METHOD) //表示注解只能写在方法上
public @interface AnnotationDemo2 {
// 给name赋默认值。也可以不给默认值
// public String name() default "aaaa";
public String name();
public int age();
}
================================
@AnnotationDemo2(name = "aaaa",age=6666)//此行报错
public class MyAnnotation2 {
@AnnotationDemo2(name = "aaaa",age=6666)//此行报错
private String name;
private int age;
@AnnotationDemo2(name = "aaaa",age=6666)
public void method01(){
System.out.println("这是方法1");
}
}
Retention:
作用:用来标识注解的生命周期(有效范围)
可使用的值定义在RetentionPolicy枚举类中,常用值如下
- SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
- CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
- RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo2 {
// 给name赋默认值。也可以不给默认值
// public String name() default "aaaa";
public String name();
public int age();
}
37.4 注解的解析
案例:模拟Junit框架
需求:
- 定义若干个方法,只需要加了MyTest注解,就可以在启动时被触发执行
分析:
- 定义一个自定义注解MyTest,只能注解方法,存活范围是一直都在的
- 定义若干方法,只要有@MyTest注解的方法就能在启动时被触发执行,没有@MyTest注解的方法不能执行
代码实现:
//注解只能写在方法上
@Target(ElementType.METHOD)
// 表示注解在任何时期都存在
//如果写Source,只能在源码阶段存在,利用反射无法解析
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
========================================================
public class MyTestDemo {
//程序运行之后自动运行method01方法
@MyTest
public void method01(){
System.out.println("这是方法1");
}
public void method02(){
System.out.println("这是方法2");
}
}
==========================================
public class MyAnnoTest {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {
// 1.获取MyTestDemo类的字节码文件对象
Class<?> aClass = Class.forName("annotation.MyTestDemo");
MyTestDemo mtd = new MyTestDemo();
// 2.获取aClass对象中所有的方法
Method[] methods = aClass.getDeclaredMethods();
// 3.遍历得到每一个方法
for (Method method : methods) {
// 4.修改临时权限
method.setAccessible(true);
// 5.判断当前方法上有没有MyTest注解
if(method.isAnnotationPresent(MyTest.class)){
method.invoke(mtd);
}
}
}
}
//运行结果:这是方法1