注解
1. 概述
定义
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用
- 编写文档:通过代码里标志的注解生成文档。
- 编译检查:通过代码里标志的注解让编译器能够实现基本的编译检查【Override】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
常见注解
- @author:用来标识作者名,eclipse开发工具默认的是系统用户名。
- @version:用于标识对象的版本号,适用范围:文件、类、方法。
- @Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法,父类不存在该方法,则编译失败。
2. 自定义注解
格式
public @interface 注解名称{
//属性列表
属性类型 属性名();
属性类型 属性名();
...
}
注解属性类型
- 八种基本数据类型
- String、Class、注解、枚举
- 以上所有类型的一维数组
public @interface Student {
String name(); // 姓名
int age() default 18; // 年龄
String gender() default "男"; // 性别
}
// 该注解就有了三个属性:name,age,gender
使用: 可以使用在类、成员变量、成员方法、构造方法、局部变量上。
//@Student(name = "张三",age = 19);
public class AnnoTest {
//@Student(name = "张三",age = 19);
private String var;
//@Student(name = "张三",age = 19);
public static void main(String[] args) {
//@Student(name = "张三",age = 19);
String innerVar;
}
}
3. 元注解(注解的注解)
注解的注解,指定注解的使用位置和生命周期。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
- @Target元注解
指明注解的使用位置,注解默认可以放在任何地方
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE) // 只有一个属性可以省去'value='
public @interface Target {
ElementType[] value(); // 枚举数组
}
TYPE: 用在类,接口上
FIELD:用在成员变量上
METHOD: 用在方法上
PARAMETER:用在参数上
CONSTRUCTOR:用在构造方法上
LOCAL_VARIABLE:用在局部变量上
- @Retention元注解
表示注解的生命周期,注解默认Class阶段
代码的生命周期: .java源代码 -> .class文件 -> 运行时
@Documented
@Retention(RetentionPolicy.RUNTIME) // 只有一个属性可以省去'value='
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value(); // 枚举数组
}
SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。
CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。
RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。
4. 注解解析
通过反射获得类中注解的属性, 只有实现AnnotatedElement接口的类才能获得注解。Constructor、Method、Field都实现了AnnotatedElement接口。注解必须活到运行时才能被反射获取。
AnnotatedElement接口中的方法
boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有指定的注解,有则返回true,否则返回false。
T getAnnotation(Class<T> annotationClass); 获得当前对象上指定的注解对象。
Annotation[] getAnnotations(); 获得当前对象及其从父类上继承的所有的注解对象。
Annotation[] getDeclaredAnnotations();获得当前对象上所有的注解对象,不包括父类的。
获得注解中的属性( 以Method为例 )
Method method = clazz.getMethod(Object obj,Class...args);
Annotation a = method.getAnnotations(String name);
Annotation.属性名();
案例:模拟Junit的@Test注解
@MyTest注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
AnnoDemo类
public class AnnoDemo {
@MyTest
public void actionOne(){
System.out.println("actionOne");
}
public void actionTwo(){
System.out.println("actionTwo");
}
@MyTest
public void actionThree(){
System.out.println("actionThree")
}
}
ParseDemo类
public class ParseDemo {
public static void main(String[] args) {
Class clazz = AnnoDemo.class;
Object obj = clazz.newInstance();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
boolean flag = method.isAnnotationPresent(MyTest.class);
if(flag) method.invoke(obj);
}
}
}
结果:
actionOne
actionThree